- 1 Read, Clean, Recode, Merge
- 2 Sample descriptives
- 3 Outcomes Pre-Post Intervention
- 4 PANAS (PANAS for zi1, zi3, zi5, zi7 are Pre; zi2, zi4, zi6, zi8 are Post )
- 5 IOS (Pre on begining of Etapa, Post on end of Etapa)
- 6 VAS variables (multiple measurements on each zi)
- 7 Define function Moderation
- 8 Moderation on PrePost (APS, PSS)
- 9 Session Info
Read, Clean, Recode, Merge
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Read, Clean, Recode, Unite
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
## Read files
folder_teatru <- "E:/Cinetic idei noi/A13/Date grup teatru"
folder_psiho <- "E:/Cinetic idei noi/A13/Date grup psiho"
file_teatru <- "A13 Tabel date COMPLET28ian.xlsx"
file_psiho <- "A13P Tabel centralizat.xlsx"
setwd(folder_teatru)
Data_teatru <- rio::import(file.path(folder_teatru, file_teatru),
skip = 1)
setwd(folder_psiho)
Data_psiho <- rio::import(file.path(folder_psiho, file_psiho),
skip = 1)
## Tidy up data
# Function coalesce rows: colapse when NA, unite with "_" when not NA
coalesce2 <- function(...) {
Reduce(function(x, y) {
i <- which(is.na(x))
j <- which(!is.na(x) & !is.na(y))
x[i] <- y[i]
x[j] <- paste(x[j], y[j], sep = "_")
x},
list(...))
}
colnames(Data_teatru) <- coalesce2(Data_teatru[2,], Data_teatru[3,])
Data_teatru <- Data_teatru[-c(1:3),]
colnames(Data_psiho) <- coalesce2(Data_psiho[2,], Data_psiho[3,])
Data_psiho <- Data_psiho[-c(1:3),]
## Check if both data sets have exact same column names
all.equal(colnames(Data_teatru), colnames(Data_psiho)) # not the same
diff_colname <- setdiff(colnames(Data_teatru), colnames(Data_psiho))
ind <- which(colnames(Data_teatru) == diff_colname)
colnames(Data_psiho)[ind] <- diff_colname # replace with same colname from Data_teatru
all.equal(colnames(Data_teatru), colnames(Data_psiho)) # now they are the same
## Solve duplicate names due to excel double header
# Function to paste a string before column name if it doesnt already start with that string
paste_tocolnames <- function(vec_colnames, string_paste){
ind <- grep(pattern = string_paste, vec_colnames) # ignore column that already has string patterm
vec_colnames[-ind] <- paste0(string_paste, vec_colnames[-ind]) # paste pattern to the rest of them
return(vec_colnames)
}
colnames(Data_teatru)[6:21] <- paste_tocolnames(colnames(Data_teatru)[6:21], "APS pre_")
colnames(Data_teatru)[22:35] <- paste_tocolnames(colnames(Data_teatru)[22:35], "PPS pre_")
colnames(Data_teatru)[36:55] <- paste_tocolnames(colnames(Data_teatru)[36:55], "PANAS pre_")
colnames(Data_teatru)[76:79] <- paste_tocolnames(colnames(Data_teatru)[76:79], "SRS post_")
colnames(Data_teatru)[80:99] <- paste_tocolnames(colnames(Data_teatru)[80:99], "PANAS post_")
colnames(Data_teatru)[100:113] <- paste_tocolnames(colnames(Data_teatru)[100:113], "PPS post_")
colnames(Data_teatru)[114:129] <- paste_tocolnames(colnames(Data_teatru)[114:129], "APS post_")
colnames(Data_psiho)[6:21] <- paste_tocolnames(colnames(Data_psiho)[6:21], "APS pre_")
colnames(Data_psiho)[22:35] <- paste_tocolnames(colnames(Data_psiho)[22:35], "PPS pre_")
colnames(Data_psiho)[36:55] <- paste_tocolnames(colnames(Data_psiho)[36:55], "PANAS pre_")
colnames(Data_psiho)[76:79] <- paste_tocolnames(colnames(Data_psiho)[76:79], "SRS post_")
colnames(Data_psiho)[80:99] <- paste_tocolnames(colnames(Data_psiho)[80:99], "PANAS post_")
colnames(Data_psiho)[100:113] <- paste_tocolnames(colnames(Data_psiho)[100:113], "PPS post_")
colnames(Data_psiho)[114:129] <- paste_tocolnames(colnames(Data_psiho)[114:129], "APS post_")
# as.data.frame(colnames(Data_psiho))
# as.data.frame(colnames(Data_teatru))
colnames(Data_teatru) <- enc2native(colnames(Data_teatru)) # fix encoding
colnames(Data_psiho) <- enc2native(colnames(Data_psiho))
## Recode known missing values
# str(Data_psiho, list.len = ncol(Data_psiho))
# str(Data_psiho, list.len = ncol(Data_psiho))
Data_teatru <-
Data_teatru %>%
replace(. == "/", NA) %>% # missing values are coded "/"
replace(. == "-", NA) %>% # missing values are coded "-"
replace(. == "NA", NA) # missing values are coded "NA"
Data_psiho <-
Data_psiho %>%
replace(.=="/", NA) %>% # missing values are coded "/"
replace(.=="-", NA) %>% # missing values are coded "-"
replace(. == "NA", NA) # missing values are coded "NA"
## Check for non-numeric elements in data sets
check_numeric1 <- as.data.frame(sapply(Data_teatru, varhandle::check.numeric))
check_numeric2 <- as.data.frame(sapply(Data_psiho, varhandle::check.numeric))
# sapply(check_numeric1, function(x) length(which(!x))) # look at columns with non-numeric and count of non-numeric values
# sapply(check_numeric2, function(x) length(which(!x)))
nonnumeric1 <- sapply(check_numeric1, function(x) which(!x, arr.ind = TRUE)) # find row numbers for non-numeric values
nonnumeric2 <- sapply(check_numeric2, function(x) which(!x, arr.ind = TRUE))
nonnumeric1[lapply(nonnumeric1, length) > 0] # return only columns and rown numbers were non-numeric
nonnumeric2[lapply(nonnumeric2, length) > 0]
## Recode to numeric
Data_teatru[, -c(1:5)] <- sapply(Data_teatru[, -c(1:5)], as.numeric)
Data_psiho[, -c(1:5)] <- sapply(Data_psiho[, -c(1:5)], as.numeric) # cant do this because of encoding: mutate_at(-c(1:5), ~as.numeric(.))
## Correct typos in IDs
#unique(Data_teatru$`Indicativ subiect`)
#unique(Data_psiho$`Indicativ subiect`)
Data_teatru$`Indicativ subiect`[Data_teatru$`Indicativ subiect` == "18.A.1:3"] <- "18.A.1.3"
Data_teatru$`Indicativ subiect`[Data_teatru$`Indicativ subiect` == "26.A.1.3."] <- "26.A.1.3"
Data_teatru$`Indicativ subiect`[Data_teatru$`Indicativ subiect` == "27.A.1.3."] <- "27.A.1.3"
Data_psiho$`Indicativ subiect` <- gsub(".P", "", Data_psiho$`Indicativ subiect`) # delete .P from IDs
Data_psiho$`Indicativ subiect`[Data_psiho$`Indicativ subiect` == "16.A.A.1.3"] <- "16.A.1.3"
Data_psiho$`Indicativ subiect`[Data_psiho$`Indicativ subiect` == "1.A.1.3"] <- "01.A.1.3"
Data_psiho$`Indicativ subiect`[Data_psiho$`Indicativ subiect` == "2.A.1.3"] <- "02.A.1.3"
Data_psiho$`Indicativ subiect`[Data_psiho$`Indicativ subiect` == "4.A.1.3"] <- "04.A.1.3"
Data_psiho$`Indicativ subiect`[Data_psiho$`Indicativ subiect` == "0.4.A.1.3"] <- "04.A.1.3"
Data_psiho$`Indicativ subiect`[Data_psiho$`Indicativ subiect` == "5.A.1.3"] <- "05.A.1.3"
Data_psiho$`Indicativ subiect`[Data_psiho$`Indicativ subiect` == "6.A.1.3"] <- "06.A.1.3"
Data_psiho$`Indicativ subiect`[Data_psiho$`Indicativ subiect` == "7.A.1.3"] <- "07.A.1.3"
Data_psiho$`Indicativ subiect`[Data_psiho$`Indicativ subiect` == "8.A.1.3"] <- "08.A.1.3"
Data_psiho$`Indicativ subiect`[Data_psiho$`Indicativ subiect` == "9.A.1.3"] <- "09.A.1.3"
Data_psiho$`Indicativ subiect` <- paste0(Data_psiho$`Indicativ subiect`, ".P") # add .P to all IDs
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Scoring Questionnaire and Unite
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
## Define function that calculates RowSums but only for rows with less than 10% NAs; and return NA if all row values are NA
SpecialRowSums <- function(df, napercent = .1) {
ifelse(rowSums(is.na(df)) > ncol(df) * napercent,
NA,
rowSums(df, na.rm = TRUE) * NA ^ (rowSums(!is.na(df)) == 0)
)
}
## APS: simple sum
Data_teatru$`APS pre_Total` <- SpecialRowSums(Data_teatru[ ,sprintf("APS pre_%d", 1:16)], napercent = .13) # not more than 2 NAs for 16 items
Data_teatru$`APS post_Total` <- SpecialRowSums(Data_teatru[ ,sprintf("APS post_%d", 1:16)], napercent = .13)
Data_psiho$`APS pre_Total` <- SpecialRowSums(Data_psiho[ ,sprintf("APS pre_%d", 1:16)], napercent = .13)
Data_psiho$`APS post_Total` <- SpecialRowSums(Data_psiho[ ,sprintf("APS post_%d", 1:16)], napercent = .13)
## PSS-SF 14: Items 4, 5, 6, 7, 9, 10, and 13 are scored in reverse direction.
keys_PSS <- c(1,1,1,-1,-1,-1,-1,1,-1,-1,1,1,-1,1)
Data_teatru$`PPS pre_Total` <-
SpecialRowSums(
psych::reverse.code(items = Data_teatru[ ,sprintf("PPS pre_%d", 1:14)], keys = keys_PSS, mini = 0, maxi = 4),
napercent = .1) # not more than 1 NAs for 14 items
Data_teatru$`PPS post_Total` <-
SpecialRowSums(
psych::reverse.code(items = Data_teatru[ ,sprintf("PPS post_%d", 1:14)], keys = keys_PSS, mini = 0, maxi = 4),
napercent = .1)
Data_psiho$`PPS pre_Total` <-
SpecialRowSums(
psych::reverse.code(items = Data_psiho[ ,sprintf("PPS pre_%d", 1:14)], keys = keys_PSS, mini = 0, maxi = 4),
napercent = .1) # not more than 1 NAs for 14 items
Data_psiho$`PPS post_Total` <-
SpecialRowSums(
psych::reverse.code(items = Data_psiho[ ,sprintf("PPS post_%d", 1:14)], keys = keys_PSS, mini = 0, maxi = 4),
napercent = .1)
## PANAS: Positive Affect Score = sum items 1, 3, 5, 9, 10, 12, 14, 16, 17, 19. Negative Affect Score = sum items 2, 4, 6, 7, 8, 11, 13, 15, 18, 20.
Data_teatru$`PA pre_Total` <- SpecialRowSums(Data_teatru[ ,35 + c(1,3,5,9,10,12,14,16,17,19)], napercent = .11) # not more than 1 NAs for 10 items
Data_teatru$`NA pre_Total` <- SpecialRowSums(Data_teatru[ ,35 + c(2,4,6,7,8,11,13,15,18,20)], napercent = .11)
Data_psiho$`PA pre_Total` <- SpecialRowSums(Data_psiho[ ,35 + c(1,3,5,9,10,12,14,16,17,19)], napercent = .11)
Data_psiho$`NA pre_Total` <- SpecialRowSums(Data_psiho[ ,35 + c(2,4,6,7,8,11,13,15,18,20)], napercent = .11)
Data_teatru$`PA post_Total` <- SpecialRowSums(Data_teatru[ ,79 + c(1,3,5,9,10,12,14,16,17,19)], napercent = .11)
Data_teatru$`NA post_Total` <- SpecialRowSums(Data_teatru[ ,79 + c(2,4,6,7,8,11,13,15,18,20)], napercent = .11)
Data_psiho$`PA post_Total` <- SpecialRowSums(Data_psiho[ ,79 + c(1,3,5,9,10,12,14,16,17,19)], napercent = .11)
Data_psiho$`NA post_Total` <- SpecialRowSums(Data_psiho[ ,79 + c(2,4,6,7,8,11,13,15,18,20)], napercent = .11)
# Define other grouping varibles
Data_teatru <-
Data_teatru %>%
mutate(Etapa = case_when(`Etapă, zi` %in% c("I.1", "I.2") ~ "I",
`Etapă, zi` %in% c("II.1", "II.2") ~ "II",
`Etapă, zi` %in% c("III.1", "III.2") ~ "III",
`Etapă, zi` %in% c("IV.1", "IV.2") ~ "IV",
TRUE ~ NA_character_),
Zi = case_when(`Etapă, zi` == "I.1" ~ "zi1",
`Etapă, zi` == "I.2" ~ "zi2",
`Etapă, zi` == "II.1" ~ "zi3",
`Etapă, zi` == "II.2" ~ "zi4",
`Etapă, zi` == "III.1" ~ "zi5",
`Etapă, zi` == "III.2" ~ "zi6",
`Etapă, zi` == "IV.1" ~ "zi7",
`Etapă, zi` == "IV.2" ~ "zi8",
TRUE ~ NA_character_)) %>%
unite(col = "Etapa_Zi", Etapa, Zi, remove = FALSE)
Data_psiho <-
Data_psiho %>%
mutate(Etapa = case_when(`Etapă, zi` %in% c("I.1", "I.2") ~ "I",
`Etapă, zi` %in% c("II.1", "II.2") ~ "II",
`Etapă, zi` %in% c("III.1", "III.2") ~ "III",
`Etapă, zi` %in% c("IV.1", "IV.2") ~ "IV",
TRUE ~ NA_character_),
Zi = case_when(`Etapă, zi` == "I.1" ~ "zi1",
`Etapă, zi` == "I.2" ~ "zi2",
`Etapă, zi` == "II.1" ~ "zi3",
`Etapă, zi` == "II.2" ~ "zi4",
`Etapă, zi` == "III.1" ~ "zi5",
`Etapă, zi` == "III.2" ~ "zi6",
`Etapă, zi` == "IV.1" ~ "zi7",
`Etapă, zi` == "IV.2" ~ "zi8",
TRUE ~ NA_character_)) %>%
unite(col = "Etapa_Zi", Etapa, Zi, remove = FALSE)
## Unite data sets
Data_teatru$Dataset <- rep("teatru", nrow(Data_teatru))
Data_psiho$Dataset <- rep("psiho", nrow(Data_psiho))
Data_United <- rbind(Data_teatru, Data_psiho)
Sample descriptives
## Number of subjects
## Number of subjects by Teatru/Psiho
Outcomes Pre-Post Intervention
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ OUTCOMES PRE-POST INTERVENTION ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
## Function to run all for teatru, psiho and United
func_prepost_tot <- function(df){
Data_melt <-
df[, c("Indicativ subiect", "Grupa", "Nume Prenume", "Etapă, zi",
"APS pre_Total", "APS post_Total",
"PPS pre_Total", "PPS post_Total")] %>%
gather("APS pre_Total":"PPS post_Total", key = "variable", value = "value") %>%
mutate_at(vars(c(1:5)), funs(as.factor)) %>%
mutate(variable = factor(variable, levels = c("APS pre_Total", "APS post_Total",
"PPS pre_Total", "PPS post_Total")))
# APS t test - paired
aps_ttest <-
df %>%
select(`Indicativ subiect`, `APS pre_Total`, `APS post_Total`) %>%
group_by(`Indicativ subiect`) %>%
summarise_all(funs(na.omit(.)[1])) %>% # squash rows with NAs per id
# filter_all(all_vars(!is.na(.))) %>% # drop row if any column is NA -- dont use here
do(broom::tidy(t.test(.$`APS pre_Total`,
.$`APS post_Total`,
mu = 0,
alt = "two.sided",
paired = TRUE,
conf.level = 0.95)))
aps_ttest_out <- knitr::kable(aps_ttest, caption = paste0(deparse(substitute(df)), " APS"), format = 'pandoc')
# APS plot t test - unpaired
aps_plot <-
Data_melt %>%
filter(variable %in% c("APS pre_Total", "APS post_Total")) %>%
#group_by(`Etapă, zi`) %>%
ggplot(aes(x = variable, y = value)) +
geom_boxplot() +
stat_summary(fun.data = mean_se, colour = "darkred") +
xlab("") +
ggtitle(deparse(substitute(df))) +
#facet_wrap(~`Etapă, zi`) +
ggpubr::stat_compare_means(method = "t.test",
label = "p.signif", # to avoid scientific notation of very small p-values
#paired = TRUE,
comparisons = list(c("APS pre_Total", "APS post_Total")))
# PPS t test - paired
pps_ttest <-
df %>%
select(`Indicativ subiect`, `PPS pre_Total`, `PPS post_Total`) %>%
group_by(`Indicativ subiect`) %>%
summarise_all(funs(na.omit(.)[1])) %>% # squash rows with NAs per id
# filter_all(all_vars(!is.na(.))) %>% # drop row if any column is NA -- dont use here
do(broom::tidy(t.test(.$`PPS pre_Total`,
.$`PPS post_Total`,
mu = 0,
alt = "two.sided",
paired = TRUE,
conf.level = 0.95)))
pps_ttest_out <- knitr::kable(pps_ttest, caption = paste0(deparse(substitute(df)), " PPS"), format = 'pandoc')
# PPS plot t test - unpaired
pps_plot <-
Data_melt %>%
filter(variable %in% c("PPS pre_Total", "PPS post_Total")) %>%
#group_by(`Etapă, zi`) %>%
ggplot(aes(x = variable, y = value)) +
geom_boxplot() +
stat_summary(fun.data = mean_se, colour = "darkred") +
xlab("") +
ggtitle(deparse(substitute(df))) +
#facet_wrap(~`Etapă, zi`) +
ggpubr::stat_compare_means(method = "t.test",
label = "p.signif", # to avoid scientific notation of very small p-values
#paired = TRUE,
comparisons = list(c("PPS pre_Total", "PPS post_Total")))
print(aps_ttest_out)
print(aps_plot)
print(pps_ttest_out)
print(pps_plot)
}
cat("### Teatru")
Teatru
Data_teatru APS
1.4 |
0.9058555 |
0.3803385 |
14 |
-1.914769 |
4.714769 |
Paired t-test |
two.sided |
Data_teatru PPS
-0.3 |
-0.1705189 |
0.8664048 |
19 |
-3.982333 |
3.382333 |
Paired t-test |
two.sided |
Psiho
Data_psiho APS
-1.666667 |
-1.011977 |
0.3257369 |
17 |
-5.141411 |
1.808077 |
Paired t-test |
two.sided |
Data_psiho PPS
3.3 |
1.759827 |
0.0945285 |
19 |
-0.6248056 |
7.224806 |
Paired t-test |
two.sided |
United
Data_United APS
-0.2727273 |
-0.236143 |
0.8148267 |
32 |
-2.625231 |
2.079776 |
Paired t-test |
two.sided |
Data_United PPS
1.5 |
1.152623 |
0.2560814 |
39 |
-1.132289 |
4.132289 |
Paired t-test |
two.sided |
PANAS (PANAS for zi1, zi3, zi5, zi7 are Pre; zi2, zi4, zi6, zi8 are Post )
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ OUTCOMES PRE-POST for PANAS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# PANAS for zi1, zi3, zi5, zi7 are Pre; zi2, zi4, zi6, zi8 are Post
## Function plot PANAS, compare by zi
plot_panas_zi <- function(df, pre_var, post_var){
df_modif <-
df %>%
gather(pre_var, post_var, key = "variable", value = "value")
stat.test <-
df_modif %>%
select(value, variable, Zi) %>%
tidyr::drop_na() %>% # need to remove NAs so factor level of condition can be droped as well
rstatix::t_test(value ~ Zi) %>% # automatically does pairwise, but has problems were factor levels of grouping with NA
# rstatix::adjust_pvalue() %>%
rstatix::add_significance("p") %>%
filter(p.signif != "ns")
p<-
ggplot(df_modif, aes(y = value, x = Zi)) +
ggtitle(paste0(deparse(substitute(df)), " : ", pre_var, " - " ,post_var)) +
geom_boxplot() + stat_summary(fun.data = mean_se, colour = "darkred") +
theme(axis.text.x = element_text(angle = 90, hjust = 1))
if(nrow(stat.test) > 0){
p <-
p + stat_pvalue_manual(stat.test, label = "p.signif",
y.position = seq(max(df_modif$value, na.rm = TRUE)+2, max(df_modif$value, na.rm = TRUE)*1.4,
length.out = nrow(stat.test))) # very hacky
}
return(stat.test) %>% print(n = Inf)
print(p)
}
cat("### Teatru")
Teatru
Psiho
United
IOS (Pre on begining of Etapa, Post on end of Etapa)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ IOS - pre on begining of etapa, post on end ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
## Function plot pre post data faceted by zi
plot_prepost_zi <- function(df, pre_var, post_var){
df %>%
gather(pre_var, post_var, key = "variable", value = "value") %>%
mutate(variable = factor(variable, levels = c(pre_var, post_var))) %>%
ggplot(aes(y = value, x = variable)) +
facet_wrap(~Zi, nrow = 1) +
ggtitle(deparse(substitute(df))) +
geom_boxplot() + stat_summary(fun.data = mean_se, colour = "darkred") +
theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
ggpubr::stat_compare_means(method = "t.test",
label = "p.signif", # to avoid scientific notation of very small p-values
#paired = TRUE,
comparisons = list(c(pre_var, post_var)))
}
## Function plot pre post data adjusted comparisons of all
plot_prepost_zi2 <- function(df, pre_var, post_var){
df_modif <-
df %>%
gather(pre_var, post_var, key = "variable", value = "value") %>%
mutate(variable = factor(variable, levels = c(pre_var, post_var)),
condition = interaction(variable, Zi),
condition = as.factor(condition))
stat.test <-
df_modif %>%
# group_by(`Indicativ subiect`) %>%
rstatix::t_test(value ~ condition) %>%
# rstatix::adjust_pvalue() %>%
rstatix::add_significance("p") %>%
filter(p.signif != "ns")
p <-
ggplot(df_modif, aes(y = value, x = condition)) +
ggtitle(deparse(substitute(df))) +
geom_boxplot() + stat_summary(fun.data = mean_se, colour = "darkred") +
theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
stat_pvalue_manual(stat.test, label = "p.signif",
y.position = seq(max(df_modif$value, na.rm = TRUE)+2, max(df_modif$value, na.rm = TRUE)*2,
length.out = nrow(stat.test))) # very hacky
print(p)
return(stat.test) %>% print(n = Inf)
}
# cat("## By Zi")
cat("### Teatru")
Teatru
Psiho
United
ANOVA for Baseline each Etapa
plot_anova_base <- function(df, pre_var, post_var){
df %>%
select(Etapa, Zi, pre_var, post_var) %>%
gather(pre_var, post_var, key = "variable", value = "value") %>%
mutate(variable = factor(variable, levels = c(pre_var, post_var))) %>%
filter(variable == pre_var) %>%
jmv::ANOVA(formula = value ~ Zi,
effectSize = list('eta', 'partEta')) -> anova_base
print(tibble::as.tibble(anova_base$main))
}
plot_anova_base(Data_United, "IOS pre", "IOS post")
By Etapa
plot_prepost_etapa <- function(df, pre_var, post_var){
df_modif <-
df %>%
select(Etapa, Zi, pre_var, post_var) %>%
gather(pre_var, post_var, key = "variable", value = "value") %>%
mutate(variable = factor(variable, levels = c(pre_var, post_var))) %>%
filter(variable == pre_var & Zi %in% sprintf("zi%d", seq(1, 8, by = 2)) |
variable == post_var & Zi %in% sprintf("zi%d", seq(2, 8, by = 2)))
stat.test <-
df_modif %>%
group_by(Etapa) %>%
rstatix::t_test(value ~ Zi) %>%
# rstatix::adjust_pvalue() %>%
rstatix::add_significance("p") %>%
filter(p.signif != "ns")
p <-
ggplot(data = df_modif, aes(y = value, x = variable)) +
facet_wrap(~Etapa, nrow = 1) +
ggtitle(deparse(substitute(df))) +
geom_boxplot() + stat_summary(fun.data = mean_se, colour = "darkred") +
theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
ggpubr::stat_compare_means(method = "t.test",
label = "p.signif", # to avoid scientific notation of very small p-values
#paired = TRUE,
comparisons = list(c(pre_var, post_var)))
print(p)
return(stat.test) %>% print(n = Inf)
}
plot_prepost_etapa(Data_teatru, "IOS pre", "IOS post")
VAS variables (multiple measurements on each zi)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Variables multiple measurements in zi ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
## Function plot pre-ex1-ex2-..-post data faceted by zi
plot_preexpost_zi <- function(df, pre_var, post_x1_var, post_x2_var, post_x3_var){
df_modif <-
df %>%
gather(pre_var, post_x1_var, post_x2_var, post_x3_var, key = "variable", value = "value") %>%
mutate(variable = factor(variable, levels = c(pre_var, post_x1_var, post_x2_var, post_x3_var)))
stat.test <-
df_modif %>%
group_by(Zi) %>%
tidyr::drop_na(value) %>% # filter so grouping factor levels get droped and we can compare with unevel levels
rstatix::t_test(value ~ variable) %>% # pairwise
rstatix::add_significance("p") %>%
filter(p.signif != "ns")
p<-
ggplot(df_modif, aes(y = value, x = variable)) +
facet_wrap(~Zi, nrow = 1) +
ggtitle(deparse(substitute(df))) +
geom_boxplot() + stat_summary(fun.data = mean_se, colour = "darkred") +
theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
stat_pvalue_manual(stat.test, label = "p.signif",
y.position = seq(max(df_modif$value, na.rm = TRUE)+2, max(df_modif$value, na.rm = TRUE)*2,
length.out = nrow(stat.test))) # very hacky
return(stat.test) %>% print(n = Inf)
p
}
cat("## By Zi")
VAS stres
Teatru
Psiho
United
VAS stare de bine
Teatru
Psiho
United
VAS corp
Teatru
Psiho
United
plot_preexpost_etapa <- function(df, pre_var, post_x1_var, post_x2_var, post_x3_var){
df_modif <-
df %>%
gather(pre_var, post_x1_var, post_x2_var, post_x3_var, key = "variable", value = "value") %>%
filter((variable == pre_var & Zi %in% sprintf("zi%d", seq(1, 8, by = 2))) | # pre
(variable == post_x1_var & Zi %in% c("zi2", "zi8")) | # post variations
(variable == post_x2_var & Zi == "zi4") |
(variable == post_x3_var & Zi == "zi6")) %>%
mutate(variable = case_when(stringr::str_detect(variable, "pre") ~ "pre",
stringr::str_detect(variable, "post") ~ "post")) %>%
mutate(variable = factor(variable, levels = c("pre", "post")))
stat.test <-
df_modif %>%
group_by(Etapa) %>%
tidyr::drop_na(value) %>% # filter so grouping factor levels get droped and we can compare with unevel levels
rstatix::t_test(value ~ variable) %>% # pairwise
rstatix::add_significance("p") %>%
filter(p.signif != "ns")
p<-
ggplot(df_modif, aes(y = value, x = variable)) +
facet_wrap(~Etapa, nrow = 1) +
ggtitle(deparse(substitute(df))) +
geom_boxplot() + stat_summary(fun.data = mean_se, colour = "darkred") +
theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
stat_pvalue_manual(stat.test, label = "p.signif",
y.position = seq(max(df_modif$value, na.rm = TRUE)+2, max(df_modif$value, na.rm = TRUE)*2,
length.out = nrow(stat.test))) # very hacky
print(p)
return(stat.test) %>% print(n = Inf)
}
cat("## By Etapa - Only United")
By Etapa - Only United
VAS Stres
VAS St bine
VAS St bine corp
Define function Moderation
find_mod <- function(df, dfp = NULL, num_only = TRUE, verbose = TRUE) {
count = 0
moderation_model_list <<- list()
if(num_only == TRUE){
numeric_cols <- unlist(lapply(df, is.numeric)) # get only numeric columns
df <- df[, numeric_cols]
}
# restricted permutations for Moderation - Check: choose(len_names, 3)*3
names <- colnames(df)
len_names = length(names)
if(is.null(dfp)){
dfp <- lapply(1:len_names, function(i){
tmp <- lapply(1:(len_names-1), function(j){
tmp <- lapply((j+1):len_names, function(k){
if(j != i & k != i) c(names[i], names[j], names[k])
})
do.call(rbind, tmp)
})
do.call(rbind, tmp)
})
dfp <- do.call(rbind.data.frame, dfp)
names(dfp) <- paste("var", 1:3, sep = "_")
dfp[, ] <- lapply(dfp[, ], as.character)
} else {
dfp <- dfp
}
for (row in 1:nrow(dfp)) {
results <- medmod::mod(data = df, # mod does centering automatically
dep = dfp[row, 1], mod = dfp[row, 2], pred = dfp[row, 3],
estMethod = "standard", test = TRUE,
simpleSlopeEst = FALSE, simpleSlopePlot = FALSE) # when testing use estMethod = 'bootstrap', bootstrap = 500
pmod <- as.data.frame(results$mod)[3,5]
if(pmod < 0.05 && !is.na(pmod)) {
count <- count + 1
if(verbose == TRUE) {
cat("Dependent Variable:", dfp[row, 1])
print(results$mod)
}
moderation_model_list[["Model"]][[paste("model", count, sep = "_")]] <<- as.data.frame(results$mod) # return as list of dataframes
moderation_model_list[["Syntax"]][[paste("model", count, sep = "_")]] <<- results$modelSyntax
}
}
cat("\n","Report: ", count, "significant moderations out of", row, "total tries.")
}
## ex dfp
# dfp <- data.frame(
# var1 = colnames(Data_med_melt)[grep("_post", colnames(Data_med_melt))],
# var2 = rep("Condition", 13),
# var3 = colnames(Data_med_melt)[grep("_pre", colnames(Data_med_melt))],
# stringsAsFactors = FALSE
# )
# find_med(df = Data_med_melt, dfp = dfp, num_only = FALSE)
Moderation on PrePost (APS, PSS)
PPS pre_Total |
0.73 |
0.18 |
0.41 |
1.11 |
4.04 |
0.00 |
SRS post_Rela<U+021B>ia |
-0.07 |
0.14 |
-0.37 |
0.20 |
-0.50 |
0.62 |
PPS pre_Total:SRS post_Rela<U+021B>ia |
-0.04 |
0.02 |
-0.09 |
0.00 |
-1.73 |
0.08 |
Average |
0.74 |
0.18 |
0.42 |
1.15 |
3.99 |
0.00 |
Low (-1SD) |
1.11 |
0.31 |
0.61 |
1.86 |
3.65 |
0.00 |
High (+1SD) |
0.36 |
0.26 |
-0.10 |
0.88 |
1.39 |
0.16 |
Scale for ‘colour’ is already present. Adding another scale for ‘colour’, which will replace the existing scale.
###############################################################################
## idea not used here
# filter(Zi %in% c("zi1", "zi8")) %>%
# pivot_longer(cols = matches("pre|post"), names_to = "variable", values_to = "value")
# Data_United %>%
# filter(Etapa == "I") %>%
# medmod::mod(data = .,
# dep = "PPS post_Total", mod = "IOS post", pred = "PPS pre_Total",
# estMethod = "standard", test = TRUE,
# simpleSlopeEst = FALSE, simpleSlopePlot = TRUE)
Session Info
R version 3.6.1 (2019-07-05)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 8.1 x64 (build 9600)
Matrix products: default
locale:
[1] LC_COLLATE=Romanian_Romania.1250 LC_CTYPE=Romanian_Romania.1250 LC_MONETARY=Romanian_Romania.1250 LC_NUMERIC=C
[5] LC_TIME=Romanian_Romania.1250
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] rio_0.5.16 scales_1.0.0 ggpubr_0.2.5 magrittr_1.5 tadaatoolbox_0.16.1
[6] summarytools_0.8.8 rstatix_0.2.0 broom_0.5.2 PerformanceAnalytics_1.5.2 xts_0.11-2
[11] zoo_1.8-4 psych_1.8.12 plyr_1.8.4 forcats_0.4.0 stringr_1.4.0
[16] dplyr_0.8.3 purrr_0.3.2 readr_1.3.1 tidyr_1.0.0 tibble_2.1.3
[21] ggplot2_3.2.1 tidyverse_1.2.1 papaja_0.1.0.9842 pacman_0.5.1
loaded via a namespace (and not attached):
[1] nlme_3.1-140 bitops_1.0-6 matrixStats_0.54.0 lubridate_1.7.4 httr_1.4.0 tools_3.6.1 backports_1.1.4
[8] R6_2.4.0 nortest_1.0-4 lazyeval_0.2.2 colorspace_1.4-1 withr_2.1.2 tidyselect_0.2.5 gridExtra_2.3
[15] mnormt_1.5-5 pixiedust_0.8.6 curl_3.2 compiler_3.6.1 cli_1.1.0 rvest_0.3.2 expm_0.999-3
[22] xml2_1.2.0 labeling_0.3 mvtnorm_1.0-11 quadprog_1.5-5 pbivnorm_0.6.0 digest_0.6.21 foreign_0.8-71
[29] rmarkdown_1.17 base64enc_0.1-3 pkgconfig_2.0.3 htmltools_0.3.6 highr_0.8 pwr_1.2-2 rlang_0.4.0
[36] readxl_1.1.0 rstudioapi_0.8 pryr_0.1.4 jmvcore_1.0.8 generics_0.0.2 jsonlite_1.6 zip_1.0.0
[43] car_3.0-2 RCurl_1.95-4.11 rapportools_1.0 Matrix_1.2-17 Rcpp_1.0.2 DescTools_0.99.29 munsell_0.5.0
[50] abind_1.4-5 viridis_0.5.1 lifecycle_0.1.0 stringi_1.4.3 carData_3.0-2 MASS_7.3-51.4 lavaan_0.6-3
[57] grid_3.6.1 parallel_3.6.1 crayon_1.3.4 lattice_0.20-38 haven_2.1.1 pander_0.6.3 hms_0.5.1
[64] zeallot_0.1.0 knitr_1.25 pillar_1.4.2 varhandle_2.0.4 rjson_0.2.20 boot_1.3-22 ggsignif_0.4.0
[71] stats4_3.6.1 codetools_0.2-16 glue_1.3.1 evaluate_0.14 data.table_1.11.8 modelr_0.1.5 vctrs_0.2.0
[78] cellranger_1.1.0 gtable_0.3.0 assertthat_0.2.1 xfun_0.9 openxlsx_4.1.0 viridisLite_0.3.0 medmod_1.0.0
[85] jmv_1.0.8 ellipsis_0.3.0
A work by Claudiu Papasteri
claudiu.papasteri@gmail.com
LS0tDQp0aXRsZTogIjxicj4gRHJhbWEgRXhlcmNpc2VzIiANCnN1YnRpdGxlOiAiUmVwb3J0IGZvciBUaGVhdGVyIEdyb3VwIGFuZCBQc3ljaG9sb2d5IEdyb3VwIg0KYXV0aG9yOiAiPGJyPiBDbGF1ZGl1IFBhcGFzdGVyaSINCmRhdGU6ICJgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVkICVtICVZJylgIg0Kb3V0cHV0OiANCiAgICBodG1sX25vdGVib29rOg0KICAgICAgICAgICAgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgICAgICAgICB0b2M6IHRydWUNCiAgICAgICAgICAgIHRvY19kZXB0aDogMg0KICAgICAgICAgICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlDQogICAgICAgICAgICB0aGVtZTogc3BhY2VsYWINCiAgICAgICAgICAgIGhpZ2hsaWdodDogdGFuZ28NCiAgICAgICAgICAgIGZvbnQtZmFtaWx5OiBBcmlhbA0KICAgICAgICAgICAgZmlnX3dpZHRoOiAxMA0KICAgICAgICAgICAgZmlnX2hlaWdodDogOQ0KICAgICMgcGRmX2RvY3VtZW50OiANCiAgICAgICAgICAgICMgdG9jOiB0cnVlDQogICAgICAgICAgICAjICB0b2NfZGVwdGg6IDINCiAgICAgICAgICAgICMgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQ0KICAgICAgICAgICAgIyBmb250c2l6ZTogMTFwdA0KICAgICAgICAgICAgIyBnZW9tZXRyeTogbWFyZ2luPTFpbg0KICAgICAgICAgICAgIyBmaWdfd2lkdGg6IDcNCiAgICAgICAgICAgICMgZmlnX2hlaWdodDogNg0KICAgICAgICAgICAgIyBmaWdfY2FwdGlvbjogdHJ1ZQ0KICAgICMgZ2l0aHViX2RvY3VtZW50OiANCiAgICAgICAgICAgICMgdG9jOiB0cnVlDQogICAgICAgICAgICAjIHRvY19kZXB0aDogMg0KICAgICAgICAgICAgIyBodG1sX3ByZXZpZXc6IGZhbHNlDQogICAgICAgICAgICAjIGZpZ193aWR0aDogNQ0KICAgICAgICAgICAgIyBmaWdfaGVpZ2h0OiA1DQogICAgICAgICAgICAjIGRldjoganBlZw0KLS0tDQoNCg0KPCEtLSBTZXR1cCAtLT4NCg0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCiMga2ludHIgb3B0aW9ucw0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KA0KICBjb21tZW50ID0gIiMiLA0KICBjb2xsYXBzZSA9IFRSVUUsDQogIGVjaG8gPSBUUlVFLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2UgPSBUUlVFLCBjYWNoZSA9IFRSVUUgICAgICAgIyBlY2hvID0gRmFsc2UgZm9yIGdpdGh1Yl9kb2N1bWVudCwgYnV0IHdpbGwgYmUgZm9sZGVkIGluIGh0bWxfbm90ZWJvb2sNCikNCg0KIyBHZW5lcmFsIFIgb3B0aW9ucyBhbmQgaW5mbw0Kc2V0LnNlZWQoMTExKSAgICAgICAgICAgICAgICMgaW4gY2FzZSB3ZSB1c2UgcmFuZG9taXplZCBwcm9jZWR1cmVzICAgICAgIA0Kb3B0aW9ucyhzY2lwZW4gPSA5OTkpICAgICAgICMgcG9zaXRpdmUgdmFsdWVzIGJpYXMgdG93YXJkcyBmaXhlZCBhbmQgbmVnYXRpdmUgdG93YXJkcyBzY2llbnRpZmljIG5vdGF0aW9uDQoNCiMgTG9hZCBwYWNrYWdlcw0KaWYgKCFyZXF1aXJlKCJwYWNtYW4iKSkgaW5zdGFsbC5wYWNrYWdlcygicGFjbWFuIikNCnBhY2thZ2VzIDwtIGMoDQogICJwYXBhamEiLA0KICAidGlkeXZlcnNlIiwgInBseXIiLCAgICAgIA0KICAicHN5Y2giLCAiUGVyZm9ybWFuY2VBbmFseXRpY3MiLCAgICAgICAgICANCiAgImJyb29tIiwgInJzdGF0aXgiLA0KICAic3VtbWFyeXRvb2xzIiwgInRhZGFhdG9vbGJveCIsICAgICAgICAgICANCiAgImdncGxvdDIiLCAiZ2dwdWJyIiwgInNjYWxlcyIsICAgICAgICANCiAgInJpbyINCiAgIyAsIC4uLg0KKQ0KaWYgKCFyZXF1aXJlKCJwYWNtYW4iKSkgaW5zdGFsbC5wYWNrYWdlcygicGFjbWFuIikNCnBhY21hbjo6cF9sb2FkKGNoYXIgPSBwYWNrYWdlcykNCg0KIyBUaGVtZXMgZm9yIGdncGxvdDIgcGxvdGluZyAoaGVyZSB1c2VkIEFQQSBzdHlsZSkNCnRoZW1lX3NldCh0aGVtZV9hcGEoKSkNCmBgYA0KDQoNCg0KDQoNCjwhLS0gUmVwb3J0IC0tPg0KDQoNCiMgUmVhZCwgQ2xlYW4sIFJlY29kZSwgTWVyZ2UNCg0KYGBge3IgcmVkX2NsZWFuX3JlY29kZV9tZXJnZSwgcmVzdWx0cz0naGlkZSd9DQojfn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fg0KIyBSZWFkLCBDbGVhbiwgUmVjb2RlLCBVbml0ZQ0KI35+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn4NCg0KIyMgUmVhZCBmaWxlcw0KZm9sZGVyX3RlYXRydSA8LSAiRTovQ2luZXRpYyBpZGVpIG5vaS9BMTMvRGF0ZSBncnVwIHRlYXRydSINCmZvbGRlcl9wc2lobyA8LSAiRTovQ2luZXRpYyBpZGVpIG5vaS9BMTMvRGF0ZSBncnVwIHBzaWhvIg0KZmlsZV90ZWF0cnUgPC0gIkExMyBUYWJlbCBkYXRlIENPTVBMRVQyOGlhbi54bHN4Ig0KZmlsZV9wc2lobyA8LSAiQTEzUCBUYWJlbCBjZW50cmFsaXphdC54bHN4Ig0KDQpzZXR3ZChmb2xkZXJfdGVhdHJ1KQ0KRGF0YV90ZWF0cnUgPC0gcmlvOjppbXBvcnQoZmlsZS5wYXRoKGZvbGRlcl90ZWF0cnUsIGZpbGVfdGVhdHJ1KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHNraXAgPSAxKQ0Kc2V0d2QoZm9sZGVyX3BzaWhvKQ0KRGF0YV9wc2lobyA8LSByaW86OmltcG9ydChmaWxlLnBhdGgoZm9sZGVyX3BzaWhvLCBmaWxlX3BzaWhvKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHNraXAgPSAxKQ0KDQoNCiMjIFRpZHkgdXAgZGF0YQ0KIyBGdW5jdGlvbiBjb2FsZXNjZSByb3dzOiBjb2xhcHNlIHdoZW4gTkEsIHVuaXRlIHdpdGggIl8iIHdoZW4gbm90IE5BDQpjb2FsZXNjZTIgPC0gZnVuY3Rpb24oLi4uKSB7DQogIFJlZHVjZShmdW5jdGlvbih4LCB5KSB7DQogICAgaSA8LSB3aGljaChpcy5uYSh4KSkNCiAgICBqIDwtIHdoaWNoKCFpcy5uYSh4KSAmICFpcy5uYSh5KSkNCiAgICB4W2ldIDwtIHlbaV0NCiAgICB4W2pdIDwtIHBhc3RlKHhbal0sIHlbal0sIHNlcCA9ICJfIikNCiAgICB4fSwNCiAgICBsaXN0KC4uLikpDQp9DQoNCmNvbG5hbWVzKERhdGFfdGVhdHJ1KSA8LSBjb2FsZXNjZTIoRGF0YV90ZWF0cnVbMixdLCBEYXRhX3RlYXRydVszLF0pDQpEYXRhX3RlYXRydSA8LSBEYXRhX3RlYXRydVstYygxOjMpLF0NCg0KY29sbmFtZXMoRGF0YV9wc2lobykgPC0gY29hbGVzY2UyKERhdGFfcHNpaG9bMixdLCBEYXRhX3BzaWhvWzMsXSkNCkRhdGFfcHNpaG8gPC0gRGF0YV9wc2lob1stYygxOjMpLF0NCg0KDQojIyBDaGVjayBpZiBib3RoIGRhdGEgc2V0cyBoYXZlIGV4YWN0IHNhbWUgY29sdW1uIG5hbWVzDQphbGwuZXF1YWwoY29sbmFtZXMoRGF0YV90ZWF0cnUpLCBjb2xuYW1lcyhEYXRhX3BzaWhvKSkgICAgICAgICAgICMgbm90IHRoZSBzYW1lDQpkaWZmX2NvbG5hbWUgPC0gc2V0ZGlmZihjb2xuYW1lcyhEYXRhX3RlYXRydSksIGNvbG5hbWVzKERhdGFfcHNpaG8pKQ0KaW5kIDwtIHdoaWNoKGNvbG5hbWVzKERhdGFfdGVhdHJ1KSA9PSAgZGlmZl9jb2xuYW1lKQ0KDQpjb2xuYW1lcyhEYXRhX3BzaWhvKVtpbmRdIDwtIGRpZmZfY29sbmFtZSAgICAgICAgICAgICAgICAgICAgICAgIyByZXBsYWNlIHdpdGggc2FtZSBjb2xuYW1lIGZyb20gRGF0YV90ZWF0cnUNCmFsbC5lcXVhbChjb2xuYW1lcyhEYXRhX3RlYXRydSksIGNvbG5hbWVzKERhdGFfcHNpaG8pKSAgICAgICAgICAgIyBub3cgdGhleSBhcmUgdGhlIHNhbWUNCg0KDQojIyBTb2x2ZSBkdXBsaWNhdGUgbmFtZXMgZHVlIHRvIGV4Y2VsIGRvdWJsZSBoZWFkZXINCiMgRnVuY3Rpb24gdG8gcGFzdGUgYSBzdHJpbmcgYmVmb3JlIGNvbHVtbiBuYW1lIGlmIGl0IGRvZXNudCBhbHJlYWR5IHN0YXJ0IHdpdGggdGhhdCBzdHJpbmcNCnBhc3RlX3RvY29sbmFtZXMgPC0gZnVuY3Rpb24odmVjX2NvbG5hbWVzLCBzdHJpbmdfcGFzdGUpew0KICBpbmQgPC0gZ3JlcChwYXR0ZXJuID0gc3RyaW5nX3Bhc3RlLCB2ZWNfY29sbmFtZXMpICAgICAgICAgICAgICAgICAgICMgaWdub3JlIGNvbHVtbiB0aGF0IGFscmVhZHkgaGFzIHN0cmluZyBwYXR0ZXJtDQogIHZlY19jb2xuYW1lc1staW5kXSA8LSBwYXN0ZTAoc3RyaW5nX3Bhc3RlLCB2ZWNfY29sbmFtZXNbLWluZF0pICAgICAgIyBwYXN0ZSBwYXR0ZXJuIHRvIHRoZSByZXN0IG9mIHRoZW0NCiAgcmV0dXJuKHZlY19jb2xuYW1lcykNCn0NCg0KY29sbmFtZXMoRGF0YV90ZWF0cnUpWzY6MjFdIDwtIHBhc3RlX3RvY29sbmFtZXMoY29sbmFtZXMoRGF0YV90ZWF0cnUpWzY6MjFdLCAiQVBTIHByZV8iKQ0KY29sbmFtZXMoRGF0YV90ZWF0cnUpWzIyOjM1XSA8LSBwYXN0ZV90b2NvbG5hbWVzKGNvbG5hbWVzKERhdGFfdGVhdHJ1KVsyMjozNV0sICJQUFMgcHJlXyIpDQpjb2xuYW1lcyhEYXRhX3RlYXRydSlbMzY6NTVdIDwtIHBhc3RlX3RvY29sbmFtZXMoY29sbmFtZXMoRGF0YV90ZWF0cnUpWzM2OjU1XSwgIlBBTkFTIHByZV8iKQ0KY29sbmFtZXMoRGF0YV90ZWF0cnUpWzc2Ojc5XSA8LSBwYXN0ZV90b2NvbG5hbWVzKGNvbG5hbWVzKERhdGFfdGVhdHJ1KVs3Njo3OV0sICJTUlMgcG9zdF8iKQ0KY29sbmFtZXMoRGF0YV90ZWF0cnUpWzgwOjk5XSA8LSBwYXN0ZV90b2NvbG5hbWVzKGNvbG5hbWVzKERhdGFfdGVhdHJ1KVs4MDo5OV0sICJQQU5BUyBwb3N0XyIpDQpjb2xuYW1lcyhEYXRhX3RlYXRydSlbMTAwOjExM10gPC0gcGFzdGVfdG9jb2xuYW1lcyhjb2xuYW1lcyhEYXRhX3RlYXRydSlbMTAwOjExM10sICJQUFMgcG9zdF8iKQ0KY29sbmFtZXMoRGF0YV90ZWF0cnUpWzExNDoxMjldIDwtIHBhc3RlX3RvY29sbmFtZXMoY29sbmFtZXMoRGF0YV90ZWF0cnUpWzExNDoxMjldLCAiQVBTIHBvc3RfIikNCg0KY29sbmFtZXMoRGF0YV9wc2lobylbNjoyMV0gPC0gcGFzdGVfdG9jb2xuYW1lcyhjb2xuYW1lcyhEYXRhX3BzaWhvKVs2OjIxXSwgIkFQUyBwcmVfIikNCmNvbG5hbWVzKERhdGFfcHNpaG8pWzIyOjM1XSA8LSBwYXN0ZV90b2NvbG5hbWVzKGNvbG5hbWVzKERhdGFfcHNpaG8pWzIyOjM1XSwgIlBQUyBwcmVfIikNCmNvbG5hbWVzKERhdGFfcHNpaG8pWzM2OjU1XSA8LSBwYXN0ZV90b2NvbG5hbWVzKGNvbG5hbWVzKERhdGFfcHNpaG8pWzM2OjU1XSwgIlBBTkFTIHByZV8iKQ0KY29sbmFtZXMoRGF0YV9wc2lobylbNzY6NzldIDwtIHBhc3RlX3RvY29sbmFtZXMoY29sbmFtZXMoRGF0YV9wc2lobylbNzY6NzldLCAiU1JTIHBvc3RfIikNCmNvbG5hbWVzKERhdGFfcHNpaG8pWzgwOjk5XSA8LSBwYXN0ZV90b2NvbG5hbWVzKGNvbG5hbWVzKERhdGFfcHNpaG8pWzgwOjk5XSwgIlBBTkFTIHBvc3RfIikNCmNvbG5hbWVzKERhdGFfcHNpaG8pWzEwMDoxMTNdIDwtIHBhc3RlX3RvY29sbmFtZXMoY29sbmFtZXMoRGF0YV9wc2lobylbMTAwOjExM10sICJQUFMgcG9zdF8iKQ0KY29sbmFtZXMoRGF0YV9wc2lobylbMTE0OjEyOV0gPC0gcGFzdGVfdG9jb2xuYW1lcyhjb2xuYW1lcyhEYXRhX3BzaWhvKVsxMTQ6MTI5XSwgIkFQUyBwb3N0XyIpDQojIGFzLmRhdGEuZnJhbWUoY29sbmFtZXMoRGF0YV9wc2lobykpDQojIGFzLmRhdGEuZnJhbWUoY29sbmFtZXMoRGF0YV90ZWF0cnUpKQ0KDQpjb2xuYW1lcyhEYXRhX3RlYXRydSkgPC0gZW5jMm5hdGl2ZShjb2xuYW1lcyhEYXRhX3RlYXRydSkpICAgICAgIyBmaXggZW5jb2RpbmcNCmNvbG5hbWVzKERhdGFfcHNpaG8pIDwtIGVuYzJuYXRpdmUoY29sbmFtZXMoRGF0YV9wc2lobykpDQoNCg0KIyMgUmVjb2RlIGtub3duIG1pc3NpbmcgdmFsdWVzDQojIHN0cihEYXRhX3BzaWhvLCBsaXN0LmxlbiA9IG5jb2woRGF0YV9wc2lobykpDQojIHN0cihEYXRhX3BzaWhvLCBsaXN0LmxlbiA9IG5jb2woRGF0YV9wc2lobykpDQpEYXRhX3RlYXRydSA8LQ0KICBEYXRhX3RlYXRydSAlPiUNCiAgcmVwbGFjZSguID09ICIvIiwgTkEpICU+JSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIG1pc3NpbmcgdmFsdWVzIGFyZSBjb2RlZCAiLyINCiAgcmVwbGFjZSguID09ICItIiwgTkEpICU+JSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIG1pc3NpbmcgdmFsdWVzIGFyZSBjb2RlZCAiLSINCiAgcmVwbGFjZSguID09ICJOQSIsIE5BKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIG1pc3NpbmcgdmFsdWVzIGFyZSBjb2RlZCAiTkEiDQoNCkRhdGFfcHNpaG8gPC0NCiAgRGF0YV9wc2lobyAlPiUNCiAgcmVwbGFjZSguPT0iLyIsIE5BKSAlPiUgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIG1pc3NpbmcgdmFsdWVzIGFyZSBjb2RlZCAiLyINCiAgcmVwbGFjZSguPT0iLSIsIE5BKSAlPiUgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIG1pc3NpbmcgdmFsdWVzIGFyZSBjb2RlZCAiLSINCiAgcmVwbGFjZSguID09ICJOQSIsIE5BKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIG1pc3NpbmcgdmFsdWVzIGFyZSBjb2RlZCAiTkEiDQoNCiAgDQojIyBDaGVjayBmb3Igbm9uLW51bWVyaWMgZWxlbWVudHMgaW4gZGF0YSBzZXRzDQpjaGVja19udW1lcmljMSA8LSBhcy5kYXRhLmZyYW1lKHNhcHBseShEYXRhX3RlYXRydSwgdmFyaGFuZGxlOjpjaGVjay5udW1lcmljKSkgDQpjaGVja19udW1lcmljMiA8LSBhcy5kYXRhLmZyYW1lKHNhcHBseShEYXRhX3BzaWhvLCB2YXJoYW5kbGU6OmNoZWNrLm51bWVyaWMpKQ0KIyBzYXBwbHkoY2hlY2tfbnVtZXJpYzEsIGZ1bmN0aW9uKHgpIGxlbmd0aCh3aGljaCgheCkpKSAgICAgIyBsb29rIGF0IGNvbHVtbnMgd2l0aCBub24tbnVtZXJpYyBhbmQgY291bnQgb2Ygbm9uLW51bWVyaWMgdmFsdWVzDQojIHNhcHBseShjaGVja19udW1lcmljMiwgZnVuY3Rpb24oeCkgbGVuZ3RoKHdoaWNoKCF4KSkpDQoNCm5vbm51bWVyaWMxIDwtIHNhcHBseShjaGVja19udW1lcmljMSwgZnVuY3Rpb24oeCkgd2hpY2goIXgsIGFyci5pbmQgPSBUUlVFKSkgICAgIyBmaW5kIHJvdyBudW1iZXJzIGZvciBub24tbnVtZXJpYyB2YWx1ZXMNCm5vbm51bWVyaWMyIDwtIHNhcHBseShjaGVja19udW1lcmljMiwgZnVuY3Rpb24oeCkgd2hpY2goIXgsIGFyci5pbmQgPSBUUlVFKSkgDQpub25udW1lcmljMVtsYXBwbHkobm9ubnVtZXJpYzEsIGxlbmd0aCkgPiAwXSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyByZXR1cm4gb25seSBjb2x1bW5zIGFuZCByb3duIG51bWJlcnMgd2VyZSBub24tbnVtZXJpYw0Kbm9ubnVtZXJpYzJbbGFwcGx5KG5vbm51bWVyaWMyLCBsZW5ndGgpID4gMF0NCg0KIyMgUmVjb2RlIHRvIG51bWVyaWMNCkRhdGFfdGVhdHJ1WywgLWMoMTo1KV0gPC0gc2FwcGx5KERhdGFfdGVhdHJ1WywgLWMoMTo1KV0sIGFzLm51bWVyaWMpICAgIA0KRGF0YV9wc2lob1ssIC1jKDE6NSldIDwtIHNhcHBseShEYXRhX3BzaWhvWywgLWMoMTo1KV0sIGFzLm51bWVyaWMpICAgICAjIGNhbnQgZG8gdGhpcyBiZWNhdXNlIG9mIGVuY29kaW5nOiAgbXV0YXRlX2F0KC1jKDE6NSksIH5hcy5udW1lcmljKC4pKQ0KICANCiMjIENvcnJlY3QgdHlwb3MgaW4gSURzDQojdW5pcXVlKERhdGFfdGVhdHJ1JGBJbmRpY2F0aXYgc3ViaWVjdGApDQojdW5pcXVlKERhdGFfcHNpaG8kYEluZGljYXRpdiBzdWJpZWN0YCkNCkRhdGFfdGVhdHJ1JGBJbmRpY2F0aXYgc3ViaWVjdGBbRGF0YV90ZWF0cnUkYEluZGljYXRpdiBzdWJpZWN0YCA9PSAiMTguQS4xOjMiXSA8LSAiMTguQS4xLjMiDQpEYXRhX3RlYXRydSRgSW5kaWNhdGl2IHN1YmllY3RgW0RhdGFfdGVhdHJ1JGBJbmRpY2F0aXYgc3ViaWVjdGAgPT0gIjI2LkEuMS4zLiJdIDwtICIyNi5BLjEuMyINCkRhdGFfdGVhdHJ1JGBJbmRpY2F0aXYgc3ViaWVjdGBbRGF0YV90ZWF0cnUkYEluZGljYXRpdiBzdWJpZWN0YCA9PSAiMjcuQS4xLjMuIl0gPC0gIjI3LkEuMS4zIg0KDQpEYXRhX3BzaWhvJGBJbmRpY2F0aXYgc3ViaWVjdGAgPC0gZ3N1YigiLlAiLCAiIiwgRGF0YV9wc2lobyRgSW5kaWNhdGl2IHN1YmllY3RgKSAgICAgICAgICAgICAgICMgZGVsZXRlIC5QIGZyb20gSURzDQpEYXRhX3BzaWhvJGBJbmRpY2F0aXYgc3ViaWVjdGBbRGF0YV9wc2lobyRgSW5kaWNhdGl2IHN1YmllY3RgID09ICIxNi5BLkEuMS4zIl0gPC0gIjE2LkEuMS4zIg0KRGF0YV9wc2lobyRgSW5kaWNhdGl2IHN1YmllY3RgW0RhdGFfcHNpaG8kYEluZGljYXRpdiBzdWJpZWN0YCA9PSAiMS5BLjEuMyJdIDwtICIwMS5BLjEuMyINCkRhdGFfcHNpaG8kYEluZGljYXRpdiBzdWJpZWN0YFtEYXRhX3BzaWhvJGBJbmRpY2F0aXYgc3ViaWVjdGAgPT0gIjIuQS4xLjMiXSA8LSAiMDIuQS4xLjMiDQpEYXRhX3BzaWhvJGBJbmRpY2F0aXYgc3ViaWVjdGBbRGF0YV9wc2lobyRgSW5kaWNhdGl2IHN1YmllY3RgID09ICI0LkEuMS4zIl0gPC0gIjA0LkEuMS4zIg0KRGF0YV9wc2lobyRgSW5kaWNhdGl2IHN1YmllY3RgW0RhdGFfcHNpaG8kYEluZGljYXRpdiBzdWJpZWN0YCA9PSAiMC40LkEuMS4zIl0gPC0gIjA0LkEuMS4zIg0KRGF0YV9wc2lobyRgSW5kaWNhdGl2IHN1YmllY3RgW0RhdGFfcHNpaG8kYEluZGljYXRpdiBzdWJpZWN0YCA9PSAiNS5BLjEuMyJdIDwtICIwNS5BLjEuMyINCkRhdGFfcHNpaG8kYEluZGljYXRpdiBzdWJpZWN0YFtEYXRhX3BzaWhvJGBJbmRpY2F0aXYgc3ViaWVjdGAgPT0gIjYuQS4xLjMiXSA8LSAiMDYuQS4xLjMiDQpEYXRhX3BzaWhvJGBJbmRpY2F0aXYgc3ViaWVjdGBbRGF0YV9wc2lobyRgSW5kaWNhdGl2IHN1YmllY3RgID09ICI3LkEuMS4zIl0gPC0gIjA3LkEuMS4zIg0KRGF0YV9wc2lobyRgSW5kaWNhdGl2IHN1YmllY3RgW0RhdGFfcHNpaG8kYEluZGljYXRpdiBzdWJpZWN0YCA9PSAiOC5BLjEuMyJdIDwtICIwOC5BLjEuMyINCkRhdGFfcHNpaG8kYEluZGljYXRpdiBzdWJpZWN0YFtEYXRhX3BzaWhvJGBJbmRpY2F0aXYgc3ViaWVjdGAgPT0gIjkuQS4xLjMiXSA8LSAiMDkuQS4xLjMiDQpEYXRhX3BzaWhvJGBJbmRpY2F0aXYgc3ViaWVjdGAgPC0gcGFzdGUwKERhdGFfcHNpaG8kYEluZGljYXRpdiBzdWJpZWN0YCwgIi5QIikgICAgICAgICAgICAgICAgIyBhZGQgLlAgdG8gYWxsIElEcw0KDQojfn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fg0KIyBTY29yaW5nIFF1ZXN0aW9ubmFpcmUgYW5kIFVuaXRlDQojfn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fg0KIyMgRGVmaW5lIGZ1bmN0aW9uIHRoYXQgY2FsY3VsYXRlcyBSb3dTdW1zIGJ1dCBvbmx5IGZvciByb3dzIHdpdGggbGVzcyB0aGFuIDEwJSBOQXM7IGFuZCByZXR1cm4gTkEgaWYgYWxsIHJvdyB2YWx1ZXMgYXJlIE5BIA0KU3BlY2lhbFJvd1N1bXMgPC0gZnVuY3Rpb24oZGYsIG5hcGVyY2VudCA9IC4xKSB7DQogIGlmZWxzZShyb3dTdW1zKGlzLm5hKGRmKSkgPiBuY29sKGRmKSAqIG5hcGVyY2VudCwNCiAgICAgICAgIE5BLA0KICAgICAgICAgcm93U3VtcyhkZiwgbmEucm0gPSBUUlVFKSAqIE5BIF4gKHJvd1N1bXMoIWlzLm5hKGRmKSkgPT0gMCkNCiAgKQ0KfQ0KDQojIyBBUFM6IHNpbXBsZSBzdW0NCkRhdGFfdGVhdHJ1JGBBUFMgcHJlX1RvdGFsYCA8LSBTcGVjaWFsUm93U3VtcyhEYXRhX3RlYXRydVsgLHNwcmludGYoIkFQUyBwcmVfJWQiLCAxOjE2KV0sIG5hcGVyY2VudCA9IC4xMykgICMgbm90IG1vcmUgdGhhbiAyIE5BcyBmb3IgMTYgaXRlbXMNCkRhdGFfdGVhdHJ1JGBBUFMgcG9zdF9Ub3RhbGAgPC0gU3BlY2lhbFJvd1N1bXMoRGF0YV90ZWF0cnVbICxzcHJpbnRmKCJBUFMgcG9zdF8lZCIsIDE6MTYpXSwgbmFwZXJjZW50ID0gLjEzKQ0KRGF0YV9wc2lobyRgQVBTIHByZV9Ub3RhbGAgPC0gU3BlY2lhbFJvd1N1bXMoRGF0YV9wc2lob1sgLHNwcmludGYoIkFQUyBwcmVfJWQiLCAxOjE2KV0sIG5hcGVyY2VudCA9IC4xMykNCkRhdGFfcHNpaG8kYEFQUyBwb3N0X1RvdGFsYCA8LSBTcGVjaWFsUm93U3VtcyhEYXRhX3BzaWhvWyAsc3ByaW50ZigiQVBTIHBvc3RfJWQiLCAxOjE2KV0sIG5hcGVyY2VudCA9IC4xMykNCg0KIyMgUFNTLVNGIDE0OiBJdGVtcyA0LCA1LCA2LCA3LCA5LCAxMCwgYW5kIDEzIGFyZSBzY29yZWQgaW4gcmV2ZXJzZSBkaXJlY3Rpb24uDQprZXlzX1BTUyA8LSBjKDEsMSwxLC0xLC0xLC0xLC0xLDEsLTEsLTEsMSwxLC0xLDEpDQoNCkRhdGFfdGVhdHJ1JGBQUFMgcHJlX1RvdGFsYCA8LSANCiAgU3BlY2lhbFJvd1N1bXMoDQogIHBzeWNoOjpyZXZlcnNlLmNvZGUoaXRlbXMgPSBEYXRhX3RlYXRydVsgLHNwcmludGYoIlBQUyBwcmVfJWQiLCAxOjE0KV0sIGtleXMgPSBrZXlzX1BTUywgIG1pbmkgPSAwLCBtYXhpID0gNCksDQogIG5hcGVyY2VudCA9IC4xKSAgIyBub3QgbW9yZSB0aGFuIDEgTkFzIGZvciAxNCBpdGVtcyANCkRhdGFfdGVhdHJ1JGBQUFMgcG9zdF9Ub3RhbGAgPC0gDQogIFNwZWNpYWxSb3dTdW1zKA0KICAgIHBzeWNoOjpyZXZlcnNlLmNvZGUoaXRlbXMgPSBEYXRhX3RlYXRydVsgLHNwcmludGYoIlBQUyBwb3N0XyVkIiwgMToxNCldLCBrZXlzID0ga2V5c19QU1MsICBtaW5pID0gMCwgbWF4aSA9IDQpLA0KICAgIG5hcGVyY2VudCA9IC4xKQ0KRGF0YV9wc2lobyRgUFBTIHByZV9Ub3RhbGAgPC0gDQogIFNwZWNpYWxSb3dTdW1zKA0KICAgIHBzeWNoOjpyZXZlcnNlLmNvZGUoaXRlbXMgPSBEYXRhX3BzaWhvWyAsc3ByaW50ZigiUFBTIHByZV8lZCIsIDE6MTQpXSwga2V5cyA9IGtleXNfUFNTLCAgbWluaSA9IDAsIG1heGkgPSA0KSwNCiAgICBuYXBlcmNlbnQgPSAuMSkgICMgbm90IG1vcmUgdGhhbiAxIE5BcyBmb3IgMTQgaXRlbXMgDQpEYXRhX3BzaWhvJGBQUFMgcG9zdF9Ub3RhbGAgPC0gDQogIFNwZWNpYWxSb3dTdW1zKA0KICAgIHBzeWNoOjpyZXZlcnNlLmNvZGUoaXRlbXMgPSBEYXRhX3BzaWhvWyAsc3ByaW50ZigiUFBTIHBvc3RfJWQiLCAxOjE0KV0sIGtleXMgPSBrZXlzX1BTUywgIG1pbmkgPSAwLCBtYXhpID0gNCksDQogICAgbmFwZXJjZW50ID0gLjEpDQoNCiMjIFBBTkFTOiBQb3NpdGl2ZSBBZmZlY3QgU2NvcmUgPSBzdW0gaXRlbXMgMSwgMywgNSwgOSwgMTAsIDEyLCAxNCwgMTYsIDE3LCAxOS4gTmVnYXRpdmUgQWZmZWN0IFNjb3JlID0gc3VtIGl0ZW1zIDIsIDQsIDYsIDcsIDgsIDExLCAxMywgMTUsIDE4LCAyMC4NCkRhdGFfdGVhdHJ1JGBQQSBwcmVfVG90YWxgIDwtIFNwZWNpYWxSb3dTdW1zKERhdGFfdGVhdHJ1WyAsMzUgKyBjKDEsMyw1LDksMTAsMTIsMTQsMTYsMTcsMTkpXSwgbmFwZXJjZW50ID0gLjExKSAjIG5vdCBtb3JlIHRoYW4gMSBOQXMgZm9yIDEwIGl0ZW1zDQpEYXRhX3RlYXRydSRgTkEgcHJlX1RvdGFsYCA8LSBTcGVjaWFsUm93U3VtcyhEYXRhX3RlYXRydVsgLDM1ICsgYygyLDQsNiw3LDgsMTEsMTMsMTUsMTgsMjApXSwgbmFwZXJjZW50ID0gLjExKQ0KRGF0YV9wc2lobyRgUEEgcHJlX1RvdGFsYCA8LSBTcGVjaWFsUm93U3VtcyhEYXRhX3BzaWhvWyAsMzUgKyBjKDEsMyw1LDksMTAsMTIsMTQsMTYsMTcsMTkpXSwgbmFwZXJjZW50ID0gLjExKSANCkRhdGFfcHNpaG8kYE5BIHByZV9Ub3RhbGAgPC0gU3BlY2lhbFJvd1N1bXMoRGF0YV9wc2lob1sgLDM1ICsgYygyLDQsNiw3LDgsMTEsMTMsMTUsMTgsMjApXSwgbmFwZXJjZW50ID0gLjExKQ0KDQpEYXRhX3RlYXRydSRgUEEgcG9zdF9Ub3RhbGAgPC0gU3BlY2lhbFJvd1N1bXMoRGF0YV90ZWF0cnVbICw3OSArIGMoMSwzLDUsOSwxMCwxMiwxNCwxNiwxNywxOSldLCBuYXBlcmNlbnQgPSAuMTEpIA0KRGF0YV90ZWF0cnUkYE5BIHBvc3RfVG90YWxgIDwtIFNwZWNpYWxSb3dTdW1zKERhdGFfdGVhdHJ1WyAsNzkgKyBjKDIsNCw2LDcsOCwxMSwxMywxNSwxOCwyMCldLCBuYXBlcmNlbnQgPSAuMTEpDQpEYXRhX3BzaWhvJGBQQSBwb3N0X1RvdGFsYCA8LSBTcGVjaWFsUm93U3VtcyhEYXRhX3BzaWhvWyAsNzkgKyBjKDEsMyw1LDksMTAsMTIsMTQsMTYsMTcsMTkpXSwgbmFwZXJjZW50ID0gLjExKSANCkRhdGFfcHNpaG8kYE5BIHBvc3RfVG90YWxgIDwtIFNwZWNpYWxSb3dTdW1zKERhdGFfcHNpaG9bICw3OSArIGMoMiw0LDYsNyw4LDExLDEzLDE1LDE4LDIwKV0sIG5hcGVyY2VudCA9IC4xMSkNCg0KDQojIERlZmluZSBvdGhlciBncm91cGluZyB2YXJpYmxlcw0KRGF0YV90ZWF0cnUgPC0gDQogIERhdGFfdGVhdHJ1ICU+JQ0KICAgIG11dGF0ZShFdGFwYSA9IGNhc2Vfd2hlbihgRXRhcMSDLCB6aWAgJWluJSBjKCJJLjEiLCAiSS4yIikgfiAiSSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGBFdGFwxIMsIHppYCAlaW4lIGMoIklJLjEiLCAgIklJLjIiKSB+ICJJSSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGBFdGFwxIMsIHppYCAlaW4lIGMoIklJSS4xIiwgIklJSS4yIikgfiAiSUlJIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYEV0YXDEgywgemlgICVpbiUgYygiSVYuMSIsICJJVi4yIikgfiAiSVYiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gTkFfY2hhcmFjdGVyXyksDQogICAgICAgICAgIFppID0gY2FzZV93aGVuKGBFdGFwxIMsIHppYCA9PSAiSS4xIiB+ICJ6aTEiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgYEV0YXDEgywgemlgID09ICJJLjIiIH4gInppMiIsICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgYEV0YXDEgywgemlgID09ICJJSS4xIiB+ICJ6aTMiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgYEV0YXDEgywgemlgID09ICJJSS4yIiB+ICJ6aTQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBgRXRhcMSDLCB6aWAgPT0gIklJSS4xIiB+ICJ6aTUiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgYEV0YXDEgywgemlgID09ICJJSUkuMiIgfiAiemk2IiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgIGBFdGFwxIMsIHppYCA9PSAiSVYuMSIgfiAiemk3IiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgIGBFdGFwxIMsIHppYCA9PSAiSVYuMiIgfiAiemk4IiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiBOQV9jaGFyYWN0ZXJfKSkgJT4lDQogIHVuaXRlKGNvbCA9ICJFdGFwYV9aaSIsIEV0YXBhLCBaaSwgcmVtb3ZlID0gRkFMU0UpDQoNCkRhdGFfcHNpaG8gPC0gDQogIERhdGFfcHNpaG8gJT4lDQogIG11dGF0ZShFdGFwYSA9IGNhc2Vfd2hlbihgRXRhcMSDLCB6aWAgJWluJSBjKCJJLjEiLCAiSS4yIikgfiAiSSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICBgRXRhcMSDLCB6aWAgJWluJSBjKCJJSS4xIiwgICJJSS4yIikgfiAiSUkiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgYEV0YXDEgywgemlgICVpbiUgYygiSUlJLjEiLCAiSUlJLjIiKSB+ICJJSUkiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgYEV0YXDEgywgemlgICVpbiUgYygiSVYuMSIsICJJVi4yIikgfiAiSVYiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+IE5BX2NoYXJhY3Rlcl8pLA0KICAgICAgICAgWmkgPSBjYXNlX3doZW4oYEV0YXDEgywgemlgID09ICJJLjEiIH4gInppMSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgYEV0YXDEgywgemlgID09ICJJLjIiIH4gInppMiIsICANCiAgICAgICAgICAgICAgICAgICAgICAgIGBFdGFwxIMsIHppYCA9PSAiSUkuMSIgfiAiemkzIiwgDQogICAgICAgICAgICAgICAgICAgICAgICBgRXRhcMSDLCB6aWAgPT0gIklJLjIiIH4gInppNCIsDQogICAgICAgICAgICAgICAgICAgICAgICBgRXRhcMSDLCB6aWAgPT0gIklJSS4xIiB+ICJ6aTUiLCANCiAgICAgICAgICAgICAgICAgICAgICAgIGBFdGFwxIMsIHppYCA9PSAiSUlJLjIiIH4gInppNiIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgYEV0YXDEgywgemlgID09ICJJVi4xIiB+ICJ6aTciLCANCiAgICAgICAgICAgICAgICAgICAgICAgIGBFdGFwxIMsIHppYCA9PSAiSVYuMiIgfiAiemk4IiwgDQogICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gTkFfY2hhcmFjdGVyXykpICU+JQ0KICB1bml0ZShjb2wgPSAiRXRhcGFfWmkiLCBFdGFwYSwgWmksIHJlbW92ZSA9IEZBTFNFKQ0KDQojIyBVbml0ZSBkYXRhIHNldHMNCkRhdGFfdGVhdHJ1JERhdGFzZXQgPC0gcmVwKCJ0ZWF0cnUiLCBucm93KERhdGFfdGVhdHJ1KSkNCkRhdGFfcHNpaG8kRGF0YXNldCA8LSByZXAoInBzaWhvIiwgbnJvdyhEYXRhX3BzaWhvKSkNCg0KRGF0YV9Vbml0ZWQgPC0gcmJpbmQoRGF0YV90ZWF0cnUsIERhdGFfcHNpaG8pDQpgYGANCg0KDQojIFNhbXBsZSBkZXNjcmlwdGl2ZXMNCg0KYGBge3Igc2FtcGxlX2Rlc2N9DQpjYXQoIiMjIE51bWJlciBvZiBzdWJqZWN0cyIpDQpEYXRhX1VuaXRlZCAlPiUgDQogZHBseXI6OnJlbmFtZShJRCA9IGBJbmRpY2F0aXYgc3ViaWVjdGApICU+JSANCiBkcGx5cjo6c3VtbWFyaXNlKGNvdW50ID0gZHBseXI6Om5fZGlzdGluY3QoSUQpKQ0KDQpjYXQoIiMjIE51bWJlciBvZiBzdWJqZWN0cyBieSBUZWF0cnUvUHNpaG8iKQ0KRGF0YV9Vbml0ZWQgJT4lDQogZHBseXI6OnJlbmFtZShJRCA9IGBJbmRpY2F0aXYgc3ViaWVjdGApICU+JSANCiBncm91cF9ieShEYXRhc2V0KSAlPiUNCiBkcGx5cjo6c3VtbWFyaXNlKGNvdW50ID0gZHBseXI6Om5fZGlzdGluY3QoSUQpKQ0KYGBgDQoNCiMgT3V0Y29tZXMgUHJlLVBvc3QgSW50ZXJ2ZW50aW9uDQoNCmBgYHtyIG91dGNvbWVzX2Fwc19wcHMsIGZpZy53aWR0aD02LCBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy5oZWlnaHQ9NSwgcmVzdWx0cz0nYXNpcyd9DQojfn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+ICAgT1VUQ09NRVMgUFJFLVBPU1QgSU5URVJWRU5USU9OICAgfn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fg0KIyMgRnVuY3Rpb24gdG8gcnVuIGFsbCBmb3IgdGVhdHJ1LCBwc2lobyBhbmQgVW5pdGVkDQpmdW5jX3ByZXBvc3RfdG90IDwtIGZ1bmN0aW9uKGRmKXsNCiAgDQogIERhdGFfbWVsdCA8LQ0KICAgIGRmWywgYygiSW5kaWNhdGl2IHN1YmllY3QiLCAiR3J1cGEiLCAiTnVtZSBQcmVudW1lIiwgIkV0YXDEgywgemkiLCANCiAgICAgICAgICAgIkFQUyBwcmVfVG90YWwiLCAiQVBTIHBvc3RfVG90YWwiLCANCiAgICAgICAgICAgIlBQUyBwcmVfVG90YWwiLCAiUFBTIHBvc3RfVG90YWwiKV0gJT4lIA0KICAgIGdhdGhlcigiQVBTIHByZV9Ub3RhbCI6IlBQUyBwb3N0X1RvdGFsIiwga2V5ID0gInZhcmlhYmxlIiwgdmFsdWUgPSAidmFsdWUiKSAgJT4lIA0KICAgIG11dGF0ZV9hdCh2YXJzKGMoMTo1KSksIGZ1bnMoYXMuZmFjdG9yKSkgJT4lIA0KICAgIG11dGF0ZSh2YXJpYWJsZSA9IGZhY3Rvcih2YXJpYWJsZSwgbGV2ZWxzID0gYygiQVBTIHByZV9Ub3RhbCIsICJBUFMgcG9zdF9Ub3RhbCIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUFBTIHByZV9Ub3RhbCIsICJQUFMgcG9zdF9Ub3RhbCIpKSkNCiAgDQogICMgQVBTIHQgdGVzdCAtIHBhaXJlZA0KICBhcHNfdHRlc3QgPC0gDQogICAgZGYgJT4lDQogICAgc2VsZWN0KGBJbmRpY2F0aXYgc3ViaWVjdGAsIGBBUFMgcHJlX1RvdGFsYCwgYEFQUyBwb3N0X1RvdGFsYCkgJT4lDQogICAgZ3JvdXBfYnkoYEluZGljYXRpdiBzdWJpZWN0YCkgJT4lDQogICAgc3VtbWFyaXNlX2FsbChmdW5zKG5hLm9taXQoLilbMV0pKSAlPiUgICAgICAgICAgICAgICAgICAgICAgICAjIHNxdWFzaCByb3dzIHdpdGggTkFzIHBlciBpZA0KICAgICMgZmlsdGVyX2FsbChhbGxfdmFycyghaXMubmEoLikpKSAlPiUgICAgICAgICAgICAgICAgICAgICAgICAgIyBkcm9wIHJvdyBpZiBhbnkgY29sdW1uIGlzIE5BIC0tIGRvbnQgdXNlIGhlcmUNCiAgICBkbyhicm9vbTo6dGlkeSh0LnRlc3QoLiRgQVBTIHByZV9Ub3RhbGAsDQogICAgICAgICAgICAgICAgICAgICAgICAgIC4kYEFQUyBwb3N0X1RvdGFsYCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgbXUgPSAwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBhbHQgPSAidHdvLnNpZGVkIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgcGFpcmVkID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgY29uZi5sZXZlbCA9IDAuOTUpKSkgDQogIGFwc190dGVzdF9vdXQgPC0ga25pdHI6OmthYmxlKGFwc190dGVzdCwgY2FwdGlvbiA9IHBhc3RlMChkZXBhcnNlKHN1YnN0aXR1dGUoZGYpKSwgIiBBUFMiKSwgZm9ybWF0ID0gJ3BhbmRvYycpDQogIA0KICAjIEFQUyBwbG90IHQgdGVzdCAtIHVucGFpcmVkDQogIGFwc19wbG90IDwtICAgDQogICAgRGF0YV9tZWx0ICU+JQ0KICAgIGZpbHRlcih2YXJpYWJsZSAlaW4lIGMoIkFQUyBwcmVfVG90YWwiLCAiQVBTIHBvc3RfVG90YWwiKSkgJT4lDQogICAgI2dyb3VwX2J5KGBFdGFwxIMsIHppYCkgJT4lDQogICAgZ2dwbG90KGFlcyh4ID0gdmFyaWFibGUsIHkgPSB2YWx1ZSkpICsNCiAgICBnZW9tX2JveHBsb3QoKSArDQogICAgc3RhdF9zdW1tYXJ5KGZ1bi5kYXRhID0gbWVhbl9zZSwgIGNvbG91ciA9ICJkYXJrcmVkIikgKw0KICAgIHhsYWIoIiIpICsNCiAgICBnZ3RpdGxlKGRlcGFyc2Uoc3Vic3RpdHV0ZShkZikpKSArDQogICAgI2ZhY2V0X3dyYXAofmBFdGFwxIMsIHppYCkgKw0KICAgIGdncHVicjo6c3RhdF9jb21wYXJlX21lYW5zKG1ldGhvZCA9ICJ0LnRlc3QiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbCA9ICJwLnNpZ25pZiIsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHRvIGF2b2lkIHNjaWVudGlmaWMgbm90YXRpb24gb2YgdmVyeSBzbWFsbCBwLXZhbHVlcw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICNwYWlyZWQgPSBUUlVFLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb21wYXJpc29ucyA9IGxpc3QoYygiQVBTIHByZV9Ub3RhbCIsICJBUFMgcG9zdF9Ub3RhbCIpKSkgIA0KICANCiAgDQogICMgUFBTIHQgdGVzdCAtIHBhaXJlZA0KICBwcHNfdHRlc3QgPC0gDQogICAgZGYgJT4lDQogICAgc2VsZWN0KGBJbmRpY2F0aXYgc3ViaWVjdGAsIGBQUFMgcHJlX1RvdGFsYCwgYFBQUyBwb3N0X1RvdGFsYCkgJT4lDQogICAgZ3JvdXBfYnkoYEluZGljYXRpdiBzdWJpZWN0YCkgJT4lDQogICAgc3VtbWFyaXNlX2FsbChmdW5zKG5hLm9taXQoLilbMV0pKSAlPiUgICAgICAgICAgICAgICAgICAgICAgICAjIHNxdWFzaCByb3dzIHdpdGggTkFzIHBlciBpZA0KICAgICMgZmlsdGVyX2FsbChhbGxfdmFycyghaXMubmEoLikpKSAlPiUgICAgICAgICAgICAgICAgICAgICAgICAgIyBkcm9wIHJvdyBpZiBhbnkgY29sdW1uIGlzIE5BIC0tIGRvbnQgdXNlIGhlcmUNCiAgICBkbyhicm9vbTo6dGlkeSh0LnRlc3QoLiRgUFBTIHByZV9Ub3RhbGAsDQogICAgICAgICAgICAgICAgICAgICAgICAgIC4kYFBQUyBwb3N0X1RvdGFsYCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgbXUgPSAwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBhbHQgPSAidHdvLnNpZGVkIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgcGFpcmVkID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgY29uZi5sZXZlbCA9IDAuOTUpKSkNCiAgcHBzX3R0ZXN0X291dCA8LSBrbml0cjo6a2FibGUocHBzX3R0ZXN0LCBjYXB0aW9uID0gcGFzdGUwKGRlcGFyc2Uoc3Vic3RpdHV0ZShkZikpLCAiIFBQUyIpLCBmb3JtYXQgPSAncGFuZG9jJykgDQogIA0KICAjIFBQUyBwbG90IHQgdGVzdCAtIHVucGFpcmVkDQogIHBwc19wbG90IDwtDQogICAgRGF0YV9tZWx0ICU+JQ0KICAgIGZpbHRlcih2YXJpYWJsZSAlaW4lIGMoIlBQUyBwcmVfVG90YWwiLCAiUFBTIHBvc3RfVG90YWwiKSkgJT4lDQogICAgI2dyb3VwX2J5KGBFdGFwxIMsIHppYCkgJT4lDQogICAgZ2dwbG90KGFlcyh4ID0gdmFyaWFibGUsIHkgPSB2YWx1ZSkpICsNCiAgICBnZW9tX2JveHBsb3QoKSArDQogICAgc3RhdF9zdW1tYXJ5KGZ1bi5kYXRhID0gbWVhbl9zZSwgIGNvbG91ciA9ICJkYXJrcmVkIikgKw0KICAgIHhsYWIoIiIpICsNCiAgICBnZ3RpdGxlKGRlcGFyc2Uoc3Vic3RpdHV0ZShkZikpKSArDQogICAgI2ZhY2V0X3dyYXAofmBFdGFwxIMsIHppYCkgKw0KICAgIGdncHVicjo6c3RhdF9jb21wYXJlX21lYW5zKG1ldGhvZCA9ICJ0LnRlc3QiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbCA9ICJwLnNpZ25pZiIsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHRvIGF2b2lkIHNjaWVudGlmaWMgbm90YXRpb24gb2YgdmVyeSBzbWFsbCBwLXZhbHVlcw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICNwYWlyZWQgPSBUUlVFLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb21wYXJpc29ucyA9IGxpc3QoYygiUFBTIHByZV9Ub3RhbCIsICJQUFMgcG9zdF9Ub3RhbCIpKSkgDQogIA0KICBwcmludChhcHNfdHRlc3Rfb3V0KQ0KICBwcmludChhcHNfcGxvdCkNCiAgcHJpbnQocHBzX3R0ZXN0X291dCkNCiAgcHJpbnQocHBzX3Bsb3QpDQp9DQoNCg0KY2F0KCIjIyMgVGVhdHJ1IikNCmZ1bmNfcHJlcG9zdF90b3QoRGF0YV90ZWF0cnUpDQpjYXQoIiMjIyBQc2lobyIpDQpmdW5jX3ByZXBvc3RfdG90KERhdGFfcHNpaG8pDQpjYXQoIiMjIyBVbml0ZWQiKQ0KZnVuY19wcmVwb3N0X3RvdChEYXRhX1VuaXRlZCkNCmBgYA0KDQoNCiMgUEFOQVMgKFBBTkFTIGZvciB6aTEsIHppMywgemk1LCB6aTcgYXJlIFByZTsgemkyLCB6aTQsIHppNiwgemk4IGFyZSBQb3N0ICkNCg0KYGBge3Igb3V0Y29tZV9wYW5hcywgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTksIHJlc3VsdHM9J2FzaXMnfQ0KI35+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fiAgIE9VVENPTUVTIFBSRS1QT1NUIGZvciBQQU5BUyAgICB+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+DQojIFBBTkFTIGZvciB6aTEsIHppMywgemk1LCB6aTcgYXJlIFByZTsgemkyLCB6aTQsIHppNiwgemk4IGFyZSBQb3N0IA0KIyMgRnVuY3Rpb24gcGxvdCBQQU5BUywgY29tcGFyZSBieSB6aQ0KcGxvdF9wYW5hc196aSA8LSBmdW5jdGlvbihkZiwgcHJlX3ZhciwgcG9zdF92YXIpew0KICBkZl9tb2RpZiA8LQ0KICAgIGRmICU+JQ0KICAgIGdhdGhlcihwcmVfdmFyLCBwb3N0X3Zhciwga2V5ID0gInZhcmlhYmxlIiwgdmFsdWUgPSAidmFsdWUiKSANCiAgDQogIHN0YXQudGVzdCA8LQ0KICAgIGRmX21vZGlmICU+JQ0KICAgIHNlbGVjdCh2YWx1ZSwgdmFyaWFibGUsIFppKSAlPiUNCiAgICB0aWR5cjo6ZHJvcF9uYSgpICU+JSAgICAgICAgICAgICAgICAgICAgICAgICAgIyBuZWVkIHRvIHJlbW92ZSBOQXMgc28gZmFjdG9yIGxldmVsIG9mIGNvbmRpdGlvbiBjYW4gYmUgZHJvcGVkIGFzIHdlbGwgICAgICAgICANCiAgICByc3RhdGl4Ojp0X3Rlc3QodmFsdWUgfiBaaSkgJT4lICAgICAgICAgICAgICAgICMgYXV0b21hdGljYWxseSBkb2VzIHBhaXJ3aXNlLCBidXQgaGFzIHByb2JsZW1zIHdlcmUgZmFjdG9yIGxldmVscyBvZiBncm91cGluZyB3aXRoIE5BDQogICAgIyByc3RhdGl4OjphZGp1c3RfcHZhbHVlKCkgJT4lICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICByc3RhdGl4OjphZGRfc2lnbmlmaWNhbmNlKCJwIikgJT4lICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgIGZpbHRlcihwLnNpZ25pZiAhPSAibnMiKSANCiAgDQogIHA8LQ0KICAgIGdncGxvdChkZl9tb2RpZiwgYWVzKHkgPSB2YWx1ZSwgeCA9IFppKSkgKw0KICAgIGdndGl0bGUocGFzdGUwKGRlcGFyc2Uoc3Vic3RpdHV0ZShkZikpLCAiIDogIiwgcHJlX3ZhciwgIiAtICIgLHBvc3RfdmFyKSkgKyANCiAgICBnZW9tX2JveHBsb3QoKSArIHN0YXRfc3VtbWFyeShmdW4uZGF0YSA9IG1lYW5fc2UsICBjb2xvdXIgPSAiZGFya3JlZCIpICsNCiAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpKQ0KICANCiAgaWYobnJvdyhzdGF0LnRlc3QpID4gMCl7DQogICAgcCA8LSANCiAgICAgIHAgKyBzdGF0X3B2YWx1ZV9tYW51YWwoc3RhdC50ZXN0LCBsYWJlbCA9ICJwLnNpZ25pZiIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5LnBvc2l0aW9uID0gc2VxKG1heChkZl9tb2RpZiR2YWx1ZSwgbmEucm0gPSBUUlVFKSsyLCBtYXgoZGZfbW9kaWYkdmFsdWUsIG5hLnJtID0gVFJVRSkqMS40LCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlbmd0aC5vdXQgPSBucm93KHN0YXQudGVzdCkpKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyB2ZXJ5IGhhY2t5DQogIH0NCiAgDQogIHJldHVybihzdGF0LnRlc3QpICU+JSBwcmludChuID0gSW5mKQ0KICBwcmludChwKQ0KfQ0KDQpjYXQoIiMjIyBUZWF0cnUiKQ0KcGxvdF9wYW5hc196aShEYXRhX3RlYXRydSwgIlBBIHByZV9Ub3RhbCIsICJQQSBwb3N0X1RvdGFsIikNCnBsb3RfcGFuYXNfemkoRGF0YV90ZWF0cnUsICJOQSBwcmVfVG90YWwiLCAiTkEgcG9zdF9Ub3RhbCIpDQpjYXQoIiMjIyBQc2lobyIpDQpwbG90X3BhbmFzX3ppKERhdGFfcHNpaG8sICJQQSBwcmVfVG90YWwiLCAiUEEgcG9zdF9Ub3RhbCIpDQpwbG90X3BhbmFzX3ppKERhdGFfcHNpaG8sICJOQSBwcmVfVG90YWwiLCAiTkEgcG9zdF9Ub3RhbCIpDQpjYXQoIiMjIyBVbml0ZWQiKQ0KcGxvdF9wYW5hc196aShEYXRhX1VuaXRlZCwgIlBBIHByZV9Ub3RhbCIsICJQQSBwb3N0X1RvdGFsIikNCnBsb3RfcGFuYXNfemkoRGF0YV9Vbml0ZWQsICJOQSBwcmVfVG90YWwiLCAiTkEgcG9zdF9Ub3RhbCIpDQpgYGANCg0KDQojIElPUyAoUHJlIG9uIGJlZ2luaW5nIG9mIEV0YXBhLCBQb3N0IG9uIGVuZCBvZiBFdGFwYSkNCg0KYGBge3IgaW9zLCBmaWcud2lkdGg9MTMsIGZpZy5oZWlnaHQ9MTEsIHJlc3VsdHM9J2FzaXMnfQ0KI35+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fiAgIElPUyAtIHByZSBvbiBiZWdpbmluZyBvZiBldGFwYSwgcG9zdCBvbiBlbmQgIH5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn4NCiMjIEZ1bmN0aW9uIHBsb3QgcHJlIHBvc3QgZGF0YSBmYWNldGVkIGJ5IHppDQpwbG90X3ByZXBvc3RfemkgPC0gZnVuY3Rpb24oZGYsIHByZV92YXIsIHBvc3RfdmFyKXsNCiAgZGYgJT4lDQogICAgZ2F0aGVyKHByZV92YXIsIHBvc3RfdmFyLCBrZXkgPSAidmFyaWFibGUiLCB2YWx1ZSA9ICJ2YWx1ZSIpICU+JQ0KICAgIG11dGF0ZSh2YXJpYWJsZSA9IGZhY3Rvcih2YXJpYWJsZSwgbGV2ZWxzID0gYyhwcmVfdmFyLCBwb3N0X3ZhcikpKSAlPiUNCiAgICBnZ3Bsb3QoYWVzKHkgPSB2YWx1ZSwgeCA9IHZhcmlhYmxlKSkgKw0KICAgIGZhY2V0X3dyYXAoflppLCBucm93ID0gMSkgKyANCiAgICBnZ3RpdGxlKGRlcGFyc2Uoc3Vic3RpdHV0ZShkZikpKSArIA0KICAgIGdlb21fYm94cGxvdCgpICsgc3RhdF9zdW1tYXJ5KGZ1bi5kYXRhID0gbWVhbl9zZSwgIGNvbG91ciA9ICJkYXJrcmVkIikgICsNCiAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpKSArDQogICAgZ2dwdWJyOjpzdGF0X2NvbXBhcmVfbWVhbnMobWV0aG9kID0gInQudGVzdCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSAicC5zaWduaWYiLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyB0byBhdm9pZCBzY2llbnRpZmljIG5vdGF0aW9uIG9mIHZlcnkgc21hbGwgcC12YWx1ZXMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjcGFpcmVkID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb21wYXJpc29ucyA9IGxpc3QoYyhwcmVfdmFyLCBwb3N0X3ZhcikpKQ0KfQ0KDQoNCiMjIEZ1bmN0aW9uIHBsb3QgcHJlIHBvc3QgZGF0YSBhZGp1c3RlZCBjb21wYXJpc29ucyBvZiBhbGwgDQpwbG90X3ByZXBvc3RfemkyIDwtIGZ1bmN0aW9uKGRmLCBwcmVfdmFyLCBwb3N0X3Zhcil7DQogIGRmX21vZGlmIDwtIA0KICAgIGRmICU+JQ0KICAgIGdhdGhlcihwcmVfdmFyLCBwb3N0X3Zhciwga2V5ID0gInZhcmlhYmxlIiwgdmFsdWUgPSAidmFsdWUiKSAlPiUNCiAgICBtdXRhdGUodmFyaWFibGUgPSBmYWN0b3IodmFyaWFibGUsIGxldmVscyA9IGMocHJlX3ZhciwgcG9zdF92YXIpKSwNCiAgICAgICAgICAgY29uZGl0aW9uID0gaW50ZXJhY3Rpb24odmFyaWFibGUsIFppKSwNCiAgICAgICAgICAgY29uZGl0aW9uID0gYXMuZmFjdG9yKGNvbmRpdGlvbikpIA0KICANCiAgc3RhdC50ZXN0IDwtDQogICAgZGZfbW9kaWYgJT4lDQogICAgIyBncm91cF9ieShgSW5kaWNhdGl2IHN1YmllY3RgKSAlPiUNCiAgICByc3RhdGl4Ojp0X3Rlc3QodmFsdWUgfiBjb25kaXRpb24pICU+JQ0KICAgICMgcnN0YXRpeDo6YWRqdXN0X3B2YWx1ZSgpICU+JQ0KICAgIHJzdGF0aXg6OmFkZF9zaWduaWZpY2FuY2UoInAiKSAlPiUNCiAgICBmaWx0ZXIocC5zaWduaWYgIT0gIm5zIikgDQogIA0KICBwIDwtIA0KICAgIGdncGxvdChkZl9tb2RpZiwgYWVzKHkgPSB2YWx1ZSwgeCA9IGNvbmRpdGlvbikpICsNCiAgICAgIGdndGl0bGUoZGVwYXJzZShzdWJzdGl0dXRlKGRmKSkpICsgDQogICAgICBnZW9tX2JveHBsb3QoKSArIHN0YXRfc3VtbWFyeShmdW4uZGF0YSA9IG1lYW5fc2UsICBjb2xvdXIgPSAiZGFya3JlZCIpICsNCiAgICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSkpICsNCiAgICAgIHN0YXRfcHZhbHVlX21hbnVhbChzdGF0LnRlc3QsIGxhYmVsID0gInAuc2lnbmlmIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgeS5wb3NpdGlvbiA9IHNlcShtYXgoZGZfbW9kaWYkdmFsdWUsIG5hLnJtID0gVFJVRSkrMiwgbWF4KGRmX21vZGlmJHZhbHVlLCBuYS5ybSA9IFRSVUUpKjIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVuZ3RoLm91dCA9IG5yb3coc3RhdC50ZXN0KSkpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHZlcnkgaGFja3kNCiAgDQogIHByaW50KHApDQogIHJldHVybihzdGF0LnRlc3QpICU+JSBwcmludChuID0gSW5mKQ0KICANCn0NCg0KDQojIGNhdCgiIyMgQnkgWmkiKQ0KY2F0KCIjIyMgVGVhdHJ1IikNCnBsb3RfcHJlcG9zdF96aShEYXRhX3RlYXRydSwgIklPUyBwcmUiLCAiSU9TIHBvc3QiKQ0KcGxvdF9wcmVwb3N0X3ppMihEYXRhX3RlYXRydSwgIklPUyBwcmUiLCAiSU9TIHBvc3QiKQ0KY2F0KCIjIyMgUHNpaG8iKQ0KcGxvdF9wcmVwb3N0X3ppKERhdGFfcHNpaG8sICJJT1MgcHJlIiwgIklPUyBwb3N0IikNCnBsb3RfcHJlcG9zdF96aTIoRGF0YV9wc2lobywgIklPUyBwcmUiLCAiSU9TIHBvc3QiKQ0KY2F0KCIjIyMgVW5pdGVkIikNCnBsb3RfcHJlcG9zdF96aShEYXRhX1VuaXRlZCwgIklPUyBwcmUiLCAiSU9TIHBvc3QiKQ0KcGxvdF9wcmVwb3N0X3ppMihEYXRhX1VuaXRlZCwgIklPUyBwcmUiLCAiSU9TIHBvc3QiKQ0KDQoNCmNhdCgiIyMgQU5PVkEgZm9yIEJhc2VsaW5lIGVhY2ggRXRhcGEiKQ0KcGxvdF9hbm92YV9iYXNlIDwtIGZ1bmN0aW9uKGRmLCBwcmVfdmFyLCBwb3N0X3Zhcil7DQogIGRmICU+JQ0KICAgIHNlbGVjdChFdGFwYSwgWmksIHByZV92YXIsIHBvc3RfdmFyKSAlPiUNCiAgICBnYXRoZXIocHJlX3ZhciwgcG9zdF92YXIsIGtleSA9ICJ2YXJpYWJsZSIsIHZhbHVlID0gInZhbHVlIikgJT4lDQogICAgbXV0YXRlKHZhcmlhYmxlID0gZmFjdG9yKHZhcmlhYmxlLCBsZXZlbHMgPSBjKHByZV92YXIsIHBvc3RfdmFyKSkpICU+JQ0KICAgIGZpbHRlcih2YXJpYWJsZSA9PSBwcmVfdmFyKSAgJT4lDQogICAgICANCiAgICBqbXY6OkFOT1ZBKGZvcm11bGEgPSB2YWx1ZSB+IFppLA0KICAgICAgICAgICAgICAgZWZmZWN0U2l6ZSA9IGxpc3QoJ2V0YScsICdwYXJ0RXRhJykpIC0+IGFub3ZhX2Jhc2UNCiAgICANCiAgICBwcmludCh0aWJibGU6OmFzLnRpYmJsZShhbm92YV9iYXNlJG1haW4pKQ0KfQ0KcGxvdF9hbm92YV9iYXNlKERhdGFfVW5pdGVkLCAiSU9TIHByZSIsICJJT1MgcG9zdCIpDQoNCg0KY2F0KCIjIyBCeSBFdGFwYSIpDQpwbG90X3ByZXBvc3RfZXRhcGEgPC0gZnVuY3Rpb24oZGYsIHByZV92YXIsIHBvc3RfdmFyKXsNCiAgZGZfbW9kaWYgPC0NCiAgICBkZiAlPiUNCiAgICAgIHNlbGVjdChFdGFwYSwgWmksIHByZV92YXIsIHBvc3RfdmFyKSAlPiUNCiAgICAgIGdhdGhlcihwcmVfdmFyLCBwb3N0X3Zhciwga2V5ID0gInZhcmlhYmxlIiwgdmFsdWUgPSAidmFsdWUiKSAlPiUNCiAgICAgIG11dGF0ZSh2YXJpYWJsZSA9IGZhY3Rvcih2YXJpYWJsZSwgbGV2ZWxzID0gYyhwcmVfdmFyLCBwb3N0X3ZhcikpKSAlPiUNCiAgICAgIGZpbHRlcih2YXJpYWJsZSA9PSBwcmVfdmFyICYgWmkgJWluJSBzcHJpbnRmKCJ6aSVkIiwgc2VxKDEsIDgsIGJ5ID0gMikpICB8DQogICAgICAgICAgICAgdmFyaWFibGUgPT0gcG9zdF92YXIgJiBaaSAlaW4lIHNwcmludGYoInppJWQiLCBzZXEoMiwgOCwgYnkgPSAyKSkpICANCiAgDQogIHN0YXQudGVzdCA8LSANCiAgICBkZl9tb2RpZiAlPiUgICAgIA0KICAgICAgZ3JvdXBfYnkoRXRhcGEpICU+JQ0KICAgICAgcnN0YXRpeDo6dF90ZXN0KHZhbHVlIH4gWmkpICU+JQ0KICAgICAgIyByc3RhdGl4OjphZGp1c3RfcHZhbHVlKCkgJT4lDQogICAgICByc3RhdGl4OjphZGRfc2lnbmlmaWNhbmNlKCJwIikgJT4lDQogICAgICBmaWx0ZXIocC5zaWduaWYgIT0gIm5zIikNCiAgDQogIHAgPC0gDQogICAgZ2dwbG90KGRhdGEgPSBkZl9tb2RpZiwgYWVzKHkgPSB2YWx1ZSwgeCA9IHZhcmlhYmxlKSkgKw0KICAgIGZhY2V0X3dyYXAofkV0YXBhLCBucm93ID0gMSkgKyANCiAgICBnZ3RpdGxlKGRlcGFyc2Uoc3Vic3RpdHV0ZShkZikpKSArIA0KICAgIGdlb21fYm94cGxvdCgpICsgc3RhdF9zdW1tYXJ5KGZ1bi5kYXRhID0gbWVhbl9zZSwgIGNvbG91ciA9ICJkYXJrcmVkIikgICsNCiAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpKSArDQogICAgZ2dwdWJyOjpzdGF0X2NvbXBhcmVfbWVhbnMobWV0aG9kID0gInQudGVzdCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSAicC5zaWduaWYiLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyB0byBhdm9pZCBzY2llbnRpZmljIG5vdGF0aW9uIG9mIHZlcnkgc21hbGwgcC12YWx1ZXMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjcGFpcmVkID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb21wYXJpc29ucyA9IGxpc3QoYyhwcmVfdmFyLCBwb3N0X3ZhcikpKQ0KDQogIHByaW50KHApDQogIHJldHVybihzdGF0LnRlc3QpICU+JSBwcmludChuID0gSW5mKQ0KfQ0KcGxvdF9wcmVwb3N0X2V0YXBhKERhdGFfdGVhdHJ1LCAiSU9TIHByZSIsICJJT1MgcG9zdCIpDQoNCg0KYGBgDQoNCg0KIyBWQVMgdmFyaWFibGVzIChtdWx0aXBsZSBtZWFzdXJlbWVudHMgb24gZWFjaCB6aSkNCg0KYGBge3IgdmFzX3ZhcmlhYmxlcywgZmlnLndpZHRoPTE1LCBmaWcuaGVpZ2h0PTExLCByZXN1bHRzPSdhc2lzJ30NCiN+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn4gICBWYXJpYWJsZXMgbXVsdGlwbGUgbWVhc3VyZW1lbnRzIGluIHppICAgIH5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+DQojIyBGdW5jdGlvbiBwbG90IHByZS1leDEtZXgyLS4uLXBvc3QgZGF0YSBmYWNldGVkIGJ5IHppDQpwbG90X3ByZWV4cG9zdF96aSA8LSBmdW5jdGlvbihkZiwgcHJlX3ZhciwgcG9zdF94MV92YXIsIHBvc3RfeDJfdmFyLCBwb3N0X3gzX3Zhcil7DQogIGRmX21vZGlmIDwtDQogICAgZGYgJT4lDQogICAgZ2F0aGVyKHByZV92YXIsIHBvc3RfeDFfdmFyLCBwb3N0X3gyX3ZhciwgcG9zdF94M192YXIsIGtleSA9ICJ2YXJpYWJsZSIsIHZhbHVlID0gInZhbHVlIikgJT4lDQogICAgbXV0YXRlKHZhcmlhYmxlID0gZmFjdG9yKHZhcmlhYmxlLCBsZXZlbHMgPSBjKHByZV92YXIsIHBvc3RfeDFfdmFyLCBwb3N0X3gyX3ZhciwgcG9zdF94M192YXIpKSkNCiAgICANCiAgc3RhdC50ZXN0IDwtDQogICAgZGZfbW9kaWYgJT4lDQogICAgZ3JvdXBfYnkoWmkpICU+JQ0KICAgIHRpZHlyOjpkcm9wX25hKHZhbHVlKSAlPiUgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBmaWx0ZXIgc28gZ3JvdXBpbmcgZmFjdG9yIGxldmVscyBnZXQgZHJvcGVkIGFuZCB3ZSBjYW4gY29tcGFyZSB3aXRoIHVuZXZlbCBsZXZlbHMNCiAgICByc3RhdGl4Ojp0X3Rlc3QodmFsdWUgfiB2YXJpYWJsZSkgJT4lICAgICAgICAgICAgICAgICMgcGFpcndpc2UNCiAgICByc3RhdGl4OjphZGRfc2lnbmlmaWNhbmNlKCJwIikgJT4lICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgZmlsdGVyKHAuc2lnbmlmICE9ICJucyIpIA0KICANCiAgcDwtDQogICAgZ2dwbG90KGRmX21vZGlmLCBhZXMoeSA9IHZhbHVlLCB4ID0gdmFyaWFibGUpKSArDQogICAgICBmYWNldF93cmFwKH5aaSwgbnJvdyA9IDEpICsgDQogICAgICBnZ3RpdGxlKGRlcGFyc2Uoc3Vic3RpdHV0ZShkZikpKSArIA0KICAgICAgZ2VvbV9ib3hwbG90KCkgKyBzdGF0X3N1bW1hcnkoZnVuLmRhdGEgPSBtZWFuX3NlLCAgY29sb3VyID0gImRhcmtyZWQiKSArDQogICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpKSArDQogICAgICBzdGF0X3B2YWx1ZV9tYW51YWwoc3RhdC50ZXN0LCBsYWJlbCA9ICJwLnNpZ25pZiIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgIHkucG9zaXRpb24gPSBzZXEobWF4KGRmX21vZGlmJHZhbHVlLCBuYS5ybSA9IFRSVUUpKzIsIG1heChkZl9tb2RpZiR2YWx1ZSwgbmEucm0gPSBUUlVFKSoyLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlbmd0aC5vdXQgPSBucm93KHN0YXQudGVzdCkpKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyB2ZXJ5IGhhY2t5DQogIA0KICByZXR1cm4oc3RhdC50ZXN0KSAlPiUgcHJpbnQobiA9IEluZikNCiAgcA0KfQ0KDQpjYXQoIiMjIEJ5IFppIikNCmNhdCgiIyMgVkFTIHN0cmVzIikNCmNhdCgiIyMjIFRlYXRydSIpDQpwbG90X3ByZWV4cG9zdF96aShEYXRhX3RlYXRydSwgIlZBUyBzdHJlcyBwcmUiLCAiVkFTIHN0cmVzIHBvc3QgZXgxIiwgIlZBUyBzdHJlcyBwb3N0IGV4MiIsICJWQVMgc3RyZXMgcG9zdCBleDMiKQ0KY2F0KCIjIyMgUHNpaG8iKQ0KcGxvdF9wcmVleHBvc3RfemkoRGF0YV9wc2lobywgIlZBUyBzdHJlcyBwcmUiLCAiVkFTIHN0cmVzIHBvc3QgZXgxIiwgIlZBUyBzdHJlcyBwb3N0IGV4MiIsICJWQVMgc3RyZXMgcG9zdCBleDMiKQ0KY2F0KCIjIyMgVW5pdGVkIikNCnBsb3RfcHJlZXhwb3N0X3ppKERhdGFfVW5pdGVkLCAiVkFTIHN0cmVzIHByZSIsICJWQVMgc3RyZXMgcG9zdCBleDEiLCAiVkFTIHN0cmVzIHBvc3QgZXgyIiwgIlZBUyBzdHJlcyBwb3N0IGV4MyIpDQoNCg0KY2F0KCIjIyBWQVMgc3RhcmUgZGUgYmluZSIpIA0KY2F0KCIjIyMgVGVhdHJ1IikNCnBsb3RfcHJlZXhwb3N0X3ppKERhdGFfdGVhdHJ1LCAiVkFTIHN0YXJlIGRlIGJpbmUgcHJlIiwgIlZBUyBzdGFyZSBkZSBiaW5lIHBvc3QgZXgxIiwgIlZBUyBzdGFyZSBkZSBiaW5lIHBvc3QgZXgyIiwgIlZBUyBzdGFyZSBkZSBiaW5lIHBvc3QgZXgzIikNCmNhdCgiIyMjIFBzaWhvIikNCnBsb3RfcHJlZXhwb3N0X3ppKERhdGFfcHNpaG8sICJWQVMgc3RhcmUgZGUgYmluZSBwcmUiLCAiVkFTIHN0YXJlIGRlIGJpbmUgcG9zdCBleDEiLCAiVkFTIHN0YXJlIGRlIGJpbmUgcG9zdCBleDIiLCAiVkFTIHN0YXJlIGRlIGJpbmUgcG9zdCBleDMiKQ0KY2F0KCIjIyMgVW5pdGVkIikNCnBsb3RfcHJlZXhwb3N0X3ppKERhdGFfVW5pdGVkLCAiVkFTIHN0YXJlIGRlIGJpbmUgcHJlIiwgIlZBUyBzdGFyZSBkZSBiaW5lIHBvc3QgZXgxIiwgIlZBUyBzdGFyZSBkZSBiaW5lIHBvc3QgZXgyIiwgIlZBUyBzdGFyZSBkZSBiaW5lIHBvc3QgZXgzIikNCg0KDQpjYXQoIiMjIFZBUyBjb3JwIikNCmNhdCgiIyMjIFRlYXRydSIpDQpwbG90X3ByZWV4cG9zdF96aShEYXRhX3RlYXRydSwgIlZBUyBjb3JwIHByZSIsICJWQVMgY29ycCBwb3N0IGV4MSIsICJWQVMgY29ycCBwb3N0IGV4MiIsICJWQVMgY29ycCBwb3N0IGV4MyIpDQpjYXQoIiMjIyBQc2lobyIpDQpwbG90X3ByZWV4cG9zdF96aShEYXRhX3BzaWhvLCAiVkFTIGNvcnAgcHJlIiwgIlZBUyBjb3JwIHBvc3QgZXgxIiwgIlZBUyBjb3JwIHBvc3QgZXgyIiwgIlZBUyBjb3JwIHBvc3QgZXgzIikNCmNhdCgiIyMjIFVuaXRlZCIpDQpwbG90X3ByZWV4cG9zdF96aShEYXRhX1VuaXRlZCwgIlZBUyBjb3JwIHByZSIsICJWQVMgY29ycCBwb3N0IGV4MSIsICJWQVMgY29ycCBwb3N0IGV4MiIsICJWQVMgY29ycCBwb3N0IGV4MyIpDQoNCg0KDQoNCnBsb3RfcHJlZXhwb3N0X2V0YXBhIDwtIGZ1bmN0aW9uKGRmLCBwcmVfdmFyLCBwb3N0X3gxX3ZhciwgcG9zdF94Ml92YXIsIHBvc3RfeDNfdmFyKXsNCiAgZGZfbW9kaWYgPC0NCiAgICBkZiAlPiUNCiAgICBnYXRoZXIocHJlX3ZhciwgcG9zdF94MV92YXIsIHBvc3RfeDJfdmFyLCBwb3N0X3gzX3Zhciwga2V5ID0gInZhcmlhYmxlIiwgdmFsdWUgPSAidmFsdWUiKSAlPiUNCiAgICBmaWx0ZXIoKHZhcmlhYmxlID09IHByZV92YXIgJiBaaSAlaW4lIHNwcmludGYoInppJWQiLCBzZXEoMSwgOCwgYnkgPSAyKSkpICB8ICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBwcmUgIA0KICAgICAgICAgICAodmFyaWFibGUgPT0gcG9zdF94MV92YXIgJiBaaSAlaW4lIGMoInppMiIsICJ6aTgiKSkgIHwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHBvc3QgdmFyaWF0aW9ucw0KICAgICAgICAgICAodmFyaWFibGUgPT0gcG9zdF94Ml92YXIgJiBaaSA9PSAiemk0IikgIHwNCiAgICAgICAgICAgKHZhcmlhYmxlID09IHBvc3RfeDNfdmFyICYgWmkgPT0gInppNiIpKSAgJT4lDQogICAgbXV0YXRlKHZhcmlhYmxlID0gY2FzZV93aGVuKHN0cmluZ3I6OnN0cl9kZXRlY3QodmFyaWFibGUsICJwcmUiKSB+ICJwcmUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJpbmdyOjpzdHJfZGV0ZWN0KHZhcmlhYmxlLCAicG9zdCIpIH4gInBvc3QiKSkgJT4lDQogICAgbXV0YXRlKHZhcmlhYmxlID0gZmFjdG9yKHZhcmlhYmxlLCBsZXZlbHMgPSBjKCJwcmUiLCAicG9zdCIpKSkNCg0KICBzdGF0LnRlc3QgPC0NCiAgICBkZl9tb2RpZiAlPiUNCiAgICBncm91cF9ieShFdGFwYSkgJT4lDQogICAgdGlkeXI6OmRyb3BfbmEodmFsdWUpICU+JSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGZpbHRlciBzbyBncm91cGluZyBmYWN0b3IgbGV2ZWxzIGdldCBkcm9wZWQgYW5kIHdlIGNhbiBjb21wYXJlIHdpdGggdW5ldmVsIGxldmVscw0KICAgIHJzdGF0aXg6OnRfdGVzdCh2YWx1ZSB+IHZhcmlhYmxlKSAlPiUgICAgICAgICAgICAgICAgIyBwYWlyd2lzZQ0KICAgIHJzdGF0aXg6OmFkZF9zaWduaWZpY2FuY2UoInAiKSAlPiUNCiAgICBmaWx0ZXIocC5zaWduaWYgIT0gIm5zIikNCg0KICBwPC0NCiAgICBnZ3Bsb3QoZGZfbW9kaWYsIGFlcyh5ID0gdmFsdWUsIHggPSB2YXJpYWJsZSkpICsNCiAgICAgIGZhY2V0X3dyYXAofkV0YXBhLCBucm93ID0gMSkgKw0KICAgICAgZ2d0aXRsZShkZXBhcnNlKHN1YnN0aXR1dGUoZGYpKSkgKw0KICAgICAgZ2VvbV9ib3hwbG90KCkgKyBzdGF0X3N1bW1hcnkoZnVuLmRhdGEgPSBtZWFuX3NlLCAgY29sb3VyID0gImRhcmtyZWQiKSArDQogICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpKSArDQogICAgICBzdGF0X3B2YWx1ZV9tYW51YWwoc3RhdC50ZXN0LCBsYWJlbCA9ICJwLnNpZ25pZiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgeS5wb3NpdGlvbiA9IHNlcShtYXgoZGZfbW9kaWYkdmFsdWUsIG5hLnJtID0gVFJVRSkrMiwgbWF4KGRmX21vZGlmJHZhbHVlLCBuYS5ybSA9IFRSVUUpKjIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZW5ndGgub3V0ID0gbnJvdyhzdGF0LnRlc3QpKSkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgdmVyeSBoYWNreQ0KDQogIHByaW50KHApDQogIHJldHVybihzdGF0LnRlc3QpICU+JSBwcmludChuID0gSW5mKQ0KfQ0KDQpjYXQoIiMjIEJ5IEV0YXBhIC0gT25seSBVbml0ZWQiKQ0KY2F0KCIjIyMgVkFTIFN0cmVzIikNCnBsb3RfcHJlZXhwb3N0X2V0YXBhKERhdGFfVW5pdGVkLCAiVkFTIHN0cmVzIHByZSIsICJWQVMgc3RyZXMgcG9zdCBleDEiLCAiVkFTIHN0cmVzIHBvc3QgZXgyIiwgIlZBUyBzdHJlcyBwb3N0IGV4MyIpDQpjYXQoIiMjIyBWQVMgU3QgYmluZSIpDQpwbG90X3ByZWV4cG9zdF9ldGFwYShEYXRhX1VuaXRlZCwgIlZBUyBzdGFyZSBkZSBiaW5lIHByZSIsICJWQVMgc3RhcmUgZGUgYmluZSBwb3N0IGV4MSIsICJWQVMgc3RhcmUgZGUgYmluZSBwb3N0IGV4MiIsICJWQVMgc3RhcmUgZGUgYmluZSBwb3N0IGV4MyIpDQpjYXQoIiMjIyBWQVMgU3QgYmluZSBjb3JwIikNCnBsb3RfcHJlZXhwb3N0X2V0YXBhKERhdGFfVW5pdGVkLCAiVkFTIGNvcnAgcHJlIiwgIlZBUyBjb3JwIHBvc3QgZXgxIiwgIlZBUyBjb3JwIHBvc3QgZXgyIiwgIlZBUyBjb3JwIHBvc3QgZXgzIikNCmBgYA0KDQoNCiMgRGVmaW5lIGZ1bmN0aW9uIE1vZGVyYXRpb24NCg0KYGBge3IgZGVmX2Z1bl9maW5kX21vZH0NCmZpbmRfbW9kIDwtIGZ1bmN0aW9uKGRmLCBkZnAgPSBOVUxMLCBudW1fb25seSA9IFRSVUUsIHZlcmJvc2UgPSBUUlVFKSB7DQogIGNvdW50ID0gMA0KICBtb2RlcmF0aW9uX21vZGVsX2xpc3QgPDwtIGxpc3QoKQ0KDQogIGlmKG51bV9vbmx5ID09IFRSVUUpew0KICBudW1lcmljX2NvbHMgPC0gdW5saXN0KGxhcHBseShkZiwgaXMubnVtZXJpYykpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGdldCBvbmx5IG51bWVyaWMgY29sdW1ucw0KICBkZiA8LSBkZlssIG51bWVyaWNfY29sc10NCiAgfQ0KICANCiAgIyByZXN0cmljdGVkIHBlcm11dGF0aW9ucyBmb3IgTW9kZXJhdGlvbiAtIENoZWNrOiBjaG9vc2UobGVuX25hbWVzLCAzKSozDQogIG5hbWVzIDwtIGNvbG5hbWVzKGRmKQ0KICBsZW5fbmFtZXMgPSBsZW5ndGgobmFtZXMpDQogIA0KICBpZihpcy5udWxsKGRmcCkpew0KICAgIGRmcCA8LSBsYXBwbHkoMTpsZW5fbmFtZXMsIGZ1bmN0aW9uKGkpew0KICAgICAgdG1wIDwtIGxhcHBseSgxOihsZW5fbmFtZXMtMSksIGZ1bmN0aW9uKGopew0KICAgICAgICB0bXAgPC0gbGFwcGx5KChqKzEpOmxlbl9uYW1lcywgZnVuY3Rpb24oayl7DQogICAgICAgICAgaWYoaiAhPSBpICYgayAhPSBpKSBjKG5hbWVzW2ldLCBuYW1lc1tqXSwgbmFtZXNba10pDQogICAgICAgIH0pDQogICAgICAgIGRvLmNhbGwocmJpbmQsIHRtcCkNCiAgICAgIH0pDQogICAgICBkby5jYWxsKHJiaW5kLCB0bXApDQogICAgfSkNCiAgICBkZnAgPC0gZG8uY2FsbChyYmluZC5kYXRhLmZyYW1lLCBkZnApDQogICAgbmFtZXMoZGZwKSA8LSBwYXN0ZSgidmFyIiwgMTozLCBzZXAgPSAiXyIpDQogICAgZGZwWywgXSA8LSBsYXBwbHkoZGZwWywgXSwgYXMuY2hhcmFjdGVyKSAgICANCiAgfSBlbHNlIHsNCiAgICBkZnAgPC0gZGZwDQogIH0NCiAgDQogIGZvciAocm93IGluIDE6bnJvdyhkZnApKSB7ICAgICAgICAgICAgICAgIA0KICAgIA0KICAgIHJlc3VsdHMgPC0gbWVkbW9kOjptb2QoZGF0YSA9IGRmLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgbW9kIGRvZXMgY2VudGVyaW5nIGF1dG9tYXRpY2FsbHkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgZGVwID0gZGZwW3JvdywgMV0sIG1vZCA9IGRmcFtyb3csIDJdLCBwcmVkID0gZGZwW3JvdywgM10sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICBlc3RNZXRob2QgPSAic3RhbmRhcmQiLCB0ZXN0ID0gVFJVRSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgIHNpbXBsZVNsb3BlRXN0ID0gRkFMU0UsIHNpbXBsZVNsb3BlUGxvdCA9IEZBTFNFKSAgICAgICAgICAgICAjIHdoZW4gdGVzdGluZyB1c2UgZXN0TWV0aG9kID0gJ2Jvb3RzdHJhcCcsIGJvb3RzdHJhcCA9IDUwMCANCiAgICANCiAgICBwbW9kIDwtIGFzLmRhdGEuZnJhbWUocmVzdWx0cyRtb2QpWzMsNV0NCg0KICAgIGlmKHBtb2QgPCAwLjA1ICYmICFpcy5uYShwbW9kKSkgew0KICAgICAgY291bnQgPC0gY291bnQgKyAxDQogICAgICAgIGlmKHZlcmJvc2UgPT0gVFJVRSkgew0KICAgICAgICBjYXQoIkRlcGVuZGVudCBWYXJpYWJsZToiLCBkZnBbcm93LCAxXSkNCiAgICAgICAgcHJpbnQocmVzdWx0cyRtb2QpIA0KICAgICAgICB9DQogICAgICBtb2RlcmF0aW9uX21vZGVsX2xpc3RbWyJNb2RlbCJdXVtbcGFzdGUoIm1vZGVsIiwgY291bnQsIHNlcCA9ICJfIildXSA8PC0gYXMuZGF0YS5mcmFtZShyZXN1bHRzJG1vZCkgICAjIHJldHVybiBhcyBsaXN0IG9mIGRhdGFmcmFtZXMNCiAgICAgIG1vZGVyYXRpb25fbW9kZWxfbGlzdFtbIlN5bnRheCJdXVtbcGFzdGUoIm1vZGVsIiwgY291bnQsIHNlcCA9ICJfIildXSA8PC0gcmVzdWx0cyRtb2RlbFN5bnRheA0KICAgICAgDQogICAgfQ0KICB9DQogIGNhdCgiXG4iLCJSZXBvcnQ6ICIsIGNvdW50LCAic2lnbmlmaWNhbnQgbW9kZXJhdGlvbnMgb3V0IG9mIiwgcm93LCAidG90YWwgdHJpZXMuIikNCn0NCg0KIyMgZXggZGZwDQojIGRmcCA8LSBkYXRhLmZyYW1lKA0KIyAgIHZhcjEgPSBjb2xuYW1lcyhEYXRhX21lZF9tZWx0KVtncmVwKCJfcG9zdCIsIGNvbG5hbWVzKERhdGFfbWVkX21lbHQpKV0sDQojICAgdmFyMiA9IHJlcCgiQ29uZGl0aW9uIiwgMTMpLA0KIyAgIHZhcjMgPSBjb2xuYW1lcyhEYXRhX21lZF9tZWx0KVtncmVwKCJfcHJlIiwgY29sbmFtZXMoRGF0YV9tZWRfbWVsdCkpXSwNCiMgICBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UNCiMgKQ0KIyBmaW5kX21lZChkZiA9IERhdGFfbWVkX21lbHQsIGRmcCA9IGRmcCwgbnVtX29ubHkgPSBGQUxTRSkgDQoNCmBgYA0KDQojIE1vZGVyYXRpb24gb24gUHJlUG9zdCAoQVBTLCBQU1MpDQoNCmBgYHtyIG1vZF9maW5kLCByZXN1bHRzPSdhc2lzJywgZWNobz1GQUxTRX0NCiMgTWFrZSBkYXRhZnJhbWUgb2YgdmFycyBhbmQgbW9kcw0KbW9kcyA8LSBjKCJJT1MgcG9zdCIsICJTUlMgcG9zdF9SZWxhPFUrMDIxQj5pYSIsICJTUlMgcG9zdF9HbG9iYWwiKSAgIyBkZWZpbmUgbW9kZXJhdG9ycw0KcHJlcyA8LSBjKCJQUFMgcHJlX1RvdGFsIiwgIkFQUyBwcmVfVG90YWwiKQ0KcG9zdHMgPC0gYygiUFBTIHBvc3RfVG90YWwiLCAiQVBTIHBvc3RfVG90YWwiKSAgIA0KZGZwIDwtIG1lcmdlKG1vZHMsIGNiaW5kKHByZXMsIHBvc3RzKSwgYnkgPSBOVUxMKSAgIyBieSA9IE5VTEwgY2F1c2VzIG1lcmdlIHRvIGRvIHNpbXBsZSBjb21iaW5hdG9yaWFsIGRhdGEgcmVwbGljYXRpb24NCmRmcCA8LSBkZnBbLCBjKCJwb3N0cyIsICJ4IiwgInByZXMiKV0gICAgICMgcmVvcmRlciBjb2x1bW5zIGZvciBmaW5kX21vZA0KZGZwIDwtIGRhdGEuZnJhbWUobGFwcGx5KGRmcCwgYXMuY2hhcmFjdGVyKSwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQ0KDQojIERhdGEgLSBTdW1tYXJpemluZyBnaXZlcyBtZWFucyBmb3IgcmVwZWF0ZWQgbW9kZXJhdG9ycyB3aGlsZSBwcmVwb3N0IG91dGNvbWVzIGFyZSBzdGlsbCBzYW1lIHZhbHVlcw0KbW9kX3ByZXBvc3QgPC0gDQogIERhdGFfVW5pdGVkICU+JQ0KICBzZWxlY3QoIkluZGljYXRpdiBzdWJpZWN0IiwgIkV0YXBhIiwgIlppIiwgbW9kcywgIHByZXMsIHBvc3RzKSAlPiUNCiAgZ3JvdXBfYnkoYEluZGljYXRpdiBzdWJpZWN0YCkgJT4lDQogIHN1bW1hcmlzZV9pZihpcy5udW1lcmljLCBtZWFuLCBuYS5ybSA9IFRSVUUpICU+JSAgICAgIyB0aGlzIGNyZWF0ZXMgTmFOcyB3ZXJlIHRoZXJlIHdlcmUgTkFzDQogIG11dGF0ZV9hbGwofmlmZWxzZShpcy5uYW4oLiksIE5BLCAuKSkgICAgDQogIA0KIyBGb3IgUHJlUG9zdCBPdXRjb21lIChub3QgbWVhc3VyZWQgZm9yIEV0YXBlKQ0KZmluZF9tb2QoZGYgPSBtb2RfcHJlcG9zdCwgZGZwID0gZGZwLCBudW1fb25seSA9IEZBTFNFKSAgICAjIGZvdW5kIDEgbW9kZXJhdGlvbg0KDQoNCmBgYA0KDQoNCmBgYHtyIG1vZDFzcnMsIHJlc3VsdHM9J2FzaXMnfQ0KbW9kMSA8LSANCiAgbWVkbW9kOjptb2QoZGF0YSA9IG1vZF9wcmVwb3N0LA0KICAgICAgICAgICAgICBkZXAgPSAiUFBTIHBvc3RfVG90YWwiLCBtb2QgPSAiU1JTIHBvc3RfUmVsYTxVKzAyMUI+aWEiLCBwcmVkID0gIlBQUyBwcmVfVG90YWwiLA0KICAgICAgICAgICAgICBlc3RNZXRob2QgPSAnYm9vdHN0cmFwJywgYm9vdHN0cmFwID0gNTAwLCANCiAgICAgICAgICAgICAgdGVzdCA9IFRSVUUsIGNpID0gVFJVRSwNCiAgICAgICAgICAgICAgc2ltcGxlU2xvcGVFc3QgPSBUUlVFLCBzaW1wbGVTbG9wZVBsb3QgPSBUUlVFKQ0KDQptb2QxJG1vZCAlPiUgDQogIGtuaXRyOjprYWJsZShkaWdpdHMgPSAyKSANCg0KbW9kMSRzaW1wbGVTbG9wZSRlc3RpbWF0ZXMgJT4lIA0KICBrbml0cjo6a2FibGUoZGlnaXRzID0gMikJDQoNCm1vZDEkc2ltcGxlU2xvcGUkcGxvdA0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KDQojIyBpZGVhIG5vdCB1c2VkIGhlcmUNCiAgIyBmaWx0ZXIoWmkgJWluJSBjKCJ6aTEiLCAiemk4IikpICU+JSANCiAgIyBwaXZvdF9sb25nZXIoY29scyA9IG1hdGNoZXMoInByZXxwb3N0IiksIG5hbWVzX3RvID0gInZhcmlhYmxlIiwgdmFsdWVzX3RvID0gInZhbHVlIikNCg0KDQoNCiMgRGF0YV9Vbml0ZWQgJT4lIA0KIyAgIGZpbHRlcihFdGFwYSA9PSAiSSIpICU+JQ0KIyAgIG1lZG1vZDo6bW9kKGRhdGEgPSAuLCANCiMgICAgICAgICAgICAgZGVwID0gIlBQUyBwb3N0X1RvdGFsIiwgbW9kID0gIklPUyBwb3N0IiwgcHJlZCA9ICJQUFMgcHJlX1RvdGFsIiwgDQojICAgICAgICAgICAgIGVzdE1ldGhvZCA9ICJzdGFuZGFyZCIsIHRlc3QgPSBUUlVFLCANCiMgICAgICAgICAgICAgc2ltcGxlU2xvcGVFc3QgPSBGQUxTRSwgc2ltcGxlU2xvcGVQbG90ID0gVFJVRSkNCg0KYGBgDQoNCg0KDQoNCg0KPCEtLSBTZXNzaW9uIEluZm8gYW5kIExpY2Vuc2UgLS0+DQoNCjxicj4NCg0KIyBTZXNzaW9uIEluZm8NCmBgYHtyIHNlc3Npb25faW5mbywgZWNobyA9IEZBTFNFLCByZXN1bHRzID0gJ21hcmt1cCd9DQpzZXNzaW9uSW5mbygpICAgIA0KYGBgDQoNCjwhLS0gRm9vdGVyIC0tPg0KJm5ic3A7DQo8aHIgLz4NCjxwIHN0eWxlPSJ0ZXh0LWFsaWduOiBjZW50ZXI7Ij5BIHdvcmsgYnkgPGEgaHJlZj0iaHR0cHM6Ly9naXRodWIuY29tL0NsYXVkaXVQYXBhc3RlcmkvIj5DbGF1ZGl1IFBhcGFzdGVyaTwvYT48L3A+DQo8cCBzdHlsZT0idGV4dC1hbGlnbjogY2VudGVyOyI+PHNwYW4gc3R5bGU9ImNvbG9yOiAjODA4MDgwOyI+PGVtPmNsYXVkaXUucGFwYXN0ZXJpQGdtYWlsLmNvbTwvZW0+PC9zcGFuPjwvcD4NCiZuYnNwOw0K